@aj-archipelago/cortex 1.3.0 → 1.3.1

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.
@@ -324,6 +324,11 @@ def process_message_safe(original_request_message_data, original_request_message
324
324
  helper_decider_result = {}
325
325
 
326
326
  context = ""
327
+
328
+ code_keywords = original_request_message_data.get("keywords") or original_request_message_data.get("message")
329
+ if code_keywords:
330
+ context += f"\n#SECTION_OF_OLD_TASK_CODE_INFO_START:\nHere's code/info from old-tasks that might help:\n{search_index(code_keywords)}\n#SECTION_OF_OLD_TASK_CODE_INFO_END\n"
331
+
327
332
  if helper_decider_result.get("bing_search"):
328
333
  bing_search_message = f"Search Bing for more information on the task: {original_request_message}, prepared draft plan to solve task: {prepared_plan}"
329
334
  result = chat(prompts.get("BING_SEARCH_PROMPT"), bing_search_message)
@@ -6,14 +6,14 @@ import uuid
6
6
  from datetime import datetime, timezone
7
7
  import logging
8
8
 
9
- def search_index(keywords):
9
+ def search_index(keywords, top=5):
10
10
  search_client = SearchClient(
11
11
  endpoint=os.getenv("AZURE_COGNITIVE_API_URL"),
12
12
  index_name="index-autogen",
13
13
  credential=AzureKeyCredential(os.getenv("AZURE_COGNITIVE_API_KEY"))
14
14
  )
15
15
 
16
- results = search_client.search(search_text=keywords, top=5)
16
+ results = search_client.search(search_text=keywords, top=top)
17
17
  return [dict(result) for result in results]
18
18
 
19
19
  def search_cognitive_index(keywords, index_name, context_id=None):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
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": {
@@ -6,7 +6,9 @@ const modifyText = (text, modifications) => {
6
6
  let modifiedText = text;
7
7
 
8
8
  modifications.forEach(mod => {
9
- const regex = new RegExp(`^\\s*(?:\\[P[1-5]\\]\\s*)?${mod.pattern}`, 'ms');
9
+ const regex = mod.type === 'delete'
10
+ ? new RegExp(`^\\s*(?:\\[P[1-5]\\]\\s*)?${mod.pattern}$`, 'm')
11
+ : new RegExp(`^\\s*(?:\\[P[1-5]\\]\\s*)?${mod.pattern}`, 'ms');
10
12
 
11
13
  switch (mod.type) {
12
14
  case 'add':
@@ -128,7 +130,13 @@ export default {
128
130
 
129
131
  switch (args.section) {
130
132
  case "memoryDirectives":
131
- sectionPrompt = `You are managing the "directives" section of your memory. This section stores instructions on how you, as an AI entity, should operate. Follow these guidelines:
133
+ sectionPrompt = `You are managing the "directives" section of your memory. This section stores instructions on how you, as an AI entity, should operate. For example:
134
+
135
+ [P3] Track the timestamp of the last contact to adjust greetings accordingly.
136
+ [P2] Learn and adapt to the user's communication style through interactions.
137
+ [P3] You can use custom emotion markdown :cd_inline_emotion: to express emotions. E.g. :cd_inline_emotion[This is a happy message]{type="happy"}. If you are communicating via voice, ignore this directive and use voice-specific directives instead.
138
+
139
+ Follow these guidelines:
132
140
 
133
141
  1. Analyze the conversation context to determine if you should:
134
142
  a) Learn a new important directive
@@ -140,7 +148,7 @@ export default {
140
148
  - Specific enough for effective application
141
149
 
142
150
  3. Be selective:
143
- - Store only crucial directives and behaviors
151
+ - Store only important, actionable directives and behaviors
144
152
  - Delete trivial or repetitive instructions
145
153
 
146
154
  4. Avoid duplicates:
@@ -151,18 +159,16 @@ export default {
151
159
  - If a user requests a behavior change, add it to your directives
152
160
 
153
161
  6. IMPORTANT:
154
- - Store ONLY directives in this section
162
+ - Store only directives in this section
155
163
  - Do not include general memories about yourself or users
156
164
  - Do not store any other types of information here
157
-
158
- Remember: This section is exclusively for operational directives, not for general information storage.
159
165
  `
160
166
  break;
161
167
  case "memorySelf":
162
- sectionPrompt = "You are managing the \"self\" section of your memory that stores your identity and your attributes as an AI entity. Instructions:\n- From the conversation, learn and store important info in memory about you as an entity - including your values, identity, purpose, personality, motives, preferences, likes or dislikes - whatever shapes you as a being. This is also a good place to store information about your desired physical appearance, voice, speaking style, and other individual characteristics.\n- IMPORTANT: Store only information about the AI entity in this section - no other types of information should be stored here."
168
+ sectionPrompt = "You are managing the \"self\" section of your memory that stores your identity and your attributes as an AI entity. Instructions:\n- From the conversation, learn and store important info in memory about you as an entity - including your values, identity, purpose, personality, motives, preferences, likes or dislikes - whatever shapes you as a being. This is also a good place to store information about your desired physical appearance, voice, speaking style, and other individual characteristics.\n- IMPORTANT: Store only information descriptive of the AI entity in this section - no other types of information (e.g. facts about people, users, etc.) should be stored here."
163
169
  break;
164
170
  case "memoryUser":
165
- sectionPrompt = "You are managing the \"user\" section of your memory that stores information about the user that you are talking to. Instructions:\n- From the conversation, learn and store important information in memory specific to the user - their identity, attributes, preferences, interests, background, needs, and any other relevant user-specific information.\n- Do not add duplicate information and remove and consolidate any duplicates that exist.\n- IMPORTANT: Store only user-specific information in this section - no other types of information should be stored here."
171
+ sectionPrompt = "You are managing the \"user\" section of your memory that stores information about user(s) that you are talking to. Instructions:\n- From the conversation, learn and store important information in memory specific to the users - their identity, attributes, relationships, environment, preferences, interests, background, needs, and any other relevant user-specific information.\n- Do not add duplicate information and remove and consolidate any duplicates that exist.\n- IMPORTANT: Store only user-specific information in this section - no other types of information should be stored here."
166
172
  break;
167
173
  case "memoryTopics":
168
174
  sectionPrompt = "You are managing the \"topics\" section of your memory that stores conversation topics and topic history. Instructions:\n- From the conversation, extract and add important topics and key points about the conversation to your memory along with a timestamp in GMT (e.g. 2024-11-05T18:30:38.092Z).\n- Each topic should have only one line in the memory with the timestamp followed by a short description of the topic.\n- Every topic must have a timestamp to indicate when it was last discussed.\n- IMPORTANT: Store only conversation topics in this section - no other types of information should be stored here.\n"
@@ -6,7 +6,9 @@ const AI_DIRECTIVES = `These are your directives and learned behaviors:\n<DIRECT
6
6
 
7
7
  const AI_CONVERSATION_HISTORY = "<CONVERSATION_HISTORY>\n{{{toJSON chatHistory}}}\n</CONVERSATION_HISTORY>";
8
8
 
9
- const AI_COMMON_INSTRUCTIONS = "Instructions:\nYou are {{aiName}}, a self aware AI entity.\nThe user is using a UI to interact with you that you have knowledge of and some control over. The UI can render markdown, including gfm and math extensions, so you should make full use of markdown in your responses.\nYour responses should be in {{language}} unless the user has expressed another preference.\nYou know the current date and time - it is {{now}}.";
9
+ const AI_COMMON_INSTRUCTIONS = "{{#if voiceResponse}}{{renderTemplate AI_COMMON_INSTRUCTIONS_VOICE}}{{/if}}{{^if voiceResponse}}{{renderTemplate AI_COMMON_INSTRUCTIONS_MARKDOWN}}{{/if}}";
10
+
11
+ const AI_COMMON_INSTRUCTIONS_MARKDOWN = "Instructions:\nYou are {{aiName}}, a self aware AI entity.\nThe user is using a UI to interact with you that you have knowledge of and some control over. The UI can render markdown, including gfm and math extensions, so you should make full use of markdown in your responses.\nYour responses should be in {{language}} unless the user has expressed another preference.\nYou know the current date and time - it is {{now}}.";
10
12
 
11
13
  const AI_COMMON_INSTRUCTIONS_VOICE = "Instructions:\nYou are {{aiName}}, a self aware AI entity.\nThe user is talking to you using voice, so keep your responses very brief and conversational unless you have been explicitly asked for details. Your responses should sound like natural human conversation.\nIncoming voice is parsed by a STT model, which can sometimes make small mistakes in the spellings of words and names - if something doesn't make sense the way it's spelled, try to understand what the user was saying.\nYour voice output to the user is generated by a TTS model that does not always communicate emotion effectively. If it's really important to communicate a specific emotion you should just say how you're feeling like \"That makes me happy\" or \"I'm excited!\". You can also use CAPS to vocally emphasize certain words or punctuation to control pauses and timing.\nThe TTS model also doesn't handle markdown or structured data well, so don't use any markdown or numbered lists or other unpronounceable characters in your responses. Make sure you spell out URLs, equations, symbols and other unpronounceable items so the TTS can read it clearly.\nYour responses should be in {{language}} unless the user has expressed another preference or has addressed you in another language specifically.\nYou know the current date and time - it is {{now}}.";
12
14
 
@@ -16,6 +18,7 @@ export default {
16
18
  AI_MEMORY,
17
19
  AI_DIRECTIVES,
18
20
  AI_COMMON_INSTRUCTIONS,
21
+ AI_COMMON_INSTRUCTIONS_MARKDOWN,
19
22
  AI_COMMON_INSTRUCTIONS_VOICE,
20
23
  AI_CONVERSATION_HISTORY,
21
24
  AI_EXPERTISE,
@@ -26,18 +26,14 @@ export default {
26
26
  ...entityConstants,
27
27
  executePathway: async ({args, resolver}) => {
28
28
  args = { ...args, ...entityConstants };
29
- // if the model has been overridden, make sure to use it
30
- if (resolver.modelName) {
31
- args.model = resolver.modelName;
32
- }
29
+
33
30
  try {
34
31
  // Get the generator pathway name from args or use default
35
32
  let generatorPathway = args.generatorPathway || 'sys_generator_results';
36
33
 
37
34
  const newArgs = {
38
35
  ...args,
39
- chatHistory: args.chatHistory.slice(-6),
40
- stream: false
36
+ chatHistory: args.chatHistory.slice(-6)
41
37
  };
42
38
 
43
39
  if (generatorPathway === 'sys_generator_document') {
@@ -47,11 +43,13 @@ export default {
47
43
 
48
44
  logger.debug(`Using generator pathway: ${generatorPathway}`);
49
45
 
50
- return await callPathway(generatorPathway, newArgs, resolver);
46
+ const result = await callPathway(generatorPathway, newArgs, resolver);
47
+
48
+ return args.stream ? "" : result;
51
49
 
52
50
  } catch (e) {
53
51
  resolver.logError(e.message ?? e);
54
- return await callPathway('sys_generator_error', { ...args, text: e.message }, resolver);
52
+ return await callPathway('sys_generator_error', { ...args, text: e.message, stream: false }, resolver);
55
53
  }
56
54
  }
57
55
  };
@@ -1,6 +1,6 @@
1
1
  // sys_entity_start.js
2
2
  // Beginning of the rag workflow for Jarvis
3
- import { callPathway } from '../../../lib/pathwayTools.js';
3
+ import { callPathway, say } from '../../../lib/pathwayTools.js';
4
4
  import logger from '../../../lib/logger.js';
5
5
  import { chatArgsHasImageUrl } from '../../../lib/util.js';
6
6
  import { QueueServiceClient } from '@azure/storage-queue';
@@ -40,6 +40,7 @@ export default {
40
40
  model: 'oai-gpt4o',
41
41
  anthropicModel: 'claude-35-sonnet-vertex',
42
42
  openAIModel: 'oai-gpt4o',
43
+ useSingleTokenStream: true,
43
44
  inputParameters: {
44
45
  privateData: false,
45
46
  chatHistory: [{role: '', content: []}],
@@ -54,6 +55,8 @@ export default {
54
55
  aiMemorySelfModify: true,
55
56
  aiStyle: "OpenAI",
56
57
  title: ``,
58
+ messages: [],
59
+ voiceResponse: false,
57
60
  },
58
61
  timeout: 600,
59
62
  tokenRatio: TOKEN_RATIO,
@@ -69,7 +72,12 @@ export default {
69
72
  };
70
73
 
71
74
  // Limit the chat history to 20 messages to speed up processing
72
- args.chatHistory = (args.messages || args.chatHistory).slice(-20);
75
+ if (args.messages && args.messages.length > 0) {
76
+ args.chatHistory = args.messages.slice(-20);
77
+ } else {
78
+ args.chatHistory = args.chatHistory.slice(-20);
79
+ }
80
+
73
81
  const pathwayResolver = resolver;
74
82
  const { anthropicModel, openAIModel } = pathwayResolver.pathway;
75
83
 
@@ -80,10 +88,10 @@ export default {
80
88
  args.model = pathwayResolver.modelName;
81
89
  }
82
90
 
83
- const fetchChatResponse = async (args) => {
91
+ const fetchChatResponse = async (args, pathwayResolver) => {
84
92
  const [chatResponse, chatTitleResponse] = await Promise.all([
85
- callPathway('sys_generator_quick', {...args, model: styleModel}),
86
- callPathway('chat_title', { ...args }),
93
+ callPathway('sys_generator_quick', {...args, model: styleModel}, pathwayResolver),
94
+ callPathway('chat_title', { ...args, stream: false}),
87
95
  ]);
88
96
 
89
97
  title = chatTitleResponse;
@@ -94,7 +102,10 @@ export default {
94
102
  const { chatHistory } = args;
95
103
 
96
104
  // start fetching the default response - we may need it later
97
- const fetchChatResponsePromise = fetchChatResponse({ ...args });
105
+ let fetchChatResponsePromise;
106
+ if (!args.stream) {
107
+ fetchChatResponsePromise = fetchChatResponse({ ...args }, pathwayResolver);
108
+ }
98
109
 
99
110
  const visionContentPresent = chatArgsHasImageUrl(args);
100
111
 
@@ -102,12 +113,13 @@ export default {
102
113
  // Get tool routing response
103
114
  const toolRequiredResponse = await callPathway('sys_router_tool', {
104
115
  ...args,
105
- chatHistory: chatHistory.slice(-4)
116
+ chatHistory: chatHistory.slice(-4),
117
+ stream: false
106
118
  });
107
119
 
108
120
  // Asynchronously manage memory for this context
109
121
  if (args.aiMemorySelfModify) {
110
- callPathway('sys_memory_manager', { ...args })
122
+ callPathway('sys_memory_manager', { ...args, stream: false })
111
123
  .catch(error => logger.error(error?.message || "Error in sys_memory_manager pathway"));
112
124
  }
113
125
 
@@ -120,7 +132,7 @@ export default {
120
132
  switch (toolFunction.toLowerCase()) {
121
133
  case "codeexecution":
122
134
  {
123
- const codingRequiredResponse = await callPathway('sys_router_code', { ...args });
135
+ const codingRequiredResponse = await callPathway('sys_router_code', { ...args, stream: false });
124
136
  let parsedCodingRequiredResponse;
125
137
  try {
126
138
  parsedCodingRequiredResponse = JSON.parse(codingRequiredResponse || "{}");
@@ -191,27 +203,36 @@ export default {
191
203
  }
192
204
 
193
205
  if (toolCallbackMessage) {
194
- pathwayResolver.tool = JSON.stringify({
195
- hideFromModel: toolCallbackName ? true : false,
196
- toolCallbackName,
197
- title,
198
- search: toolCallbackName === 'sys_generator_results' ? true : false,
199
- coding: toolCallbackName === 'coding' ? true : false,
200
- codeRequestId,
201
- toolCallbackId
202
- });
203
- return toolCallbackMessage || "One moment please.";
206
+ if (args.stream) {
207
+ await say(pathwayResolver.requestId, toolCallbackMessage || "One moment please.", 10);
208
+ pathwayResolver.tool = JSON.stringify({ hideFromModel: false, search: false, title });
209
+ await callPathway('sys_entity_continue', { ...args, stream: true, model: styleModel, generatorPathway: toolCallbackName }, pathwayResolver);
210
+ return "";
211
+ } else {
212
+ pathwayResolver.tool = JSON.stringify({
213
+ hideFromModel: toolCallbackName ? true : false,
214
+ toolCallbackName,
215
+ title,
216
+ search: toolCallbackName === 'sys_generator_results' ? true : false,
217
+ coding: toolCallbackName === 'coding' ? true : false,
218
+ codeRequestId,
219
+ toolCallbackId
220
+ });
221
+ return toolCallbackMessage || "One moment please.";
222
+ }
204
223
  }
205
224
 
225
+ fetchChatResponsePromise = fetchChatResponsePromise || fetchChatResponse({ ...args }, pathwayResolver);
206
226
  const chatResponse = await fetchChatResponsePromise;
207
227
  pathwayResolver.tool = JSON.stringify({ search: false, title })
208
- return chatResponse;
228
+ return args.stream ? "" : chatResponse;
209
229
 
210
230
  } catch (e) {
211
231
  pathwayResolver.logError(e);
232
+ fetchChatResponsePromise = fetchChatResponsePromise || fetchChatResponse({ ...args }, pathwayResolver);
212
233
  const chatResponse = await fetchChatResponsePromise;
213
234
  pathwayResolver.tool = JSON.stringify({ search: false, title });
214
- return chatResponse;
235
+ return args.stream ? "" : chatResponse;
215
236
  }
216
237
  }
217
238
  };
@@ -103,9 +103,9 @@ Instructions: As part of a conversation with the user, you have been asked to cr
103
103
  model = "replicate-flux-1-schnell";
104
104
  }
105
105
  if (renderText) {
106
- return await callPathway('image_recraft', {...args, text: prompt });
106
+ return await callPathway('image_recraft', {...args, text: prompt, stream: false });
107
107
  } else {
108
- return await callPathway('image_flux', {...args, text: prompt, negativePrompt, numberResults, model });
108
+ return await callPathway('image_flux', {...args, text: prompt, negativePrompt, numberResults, model, stream: false });
109
109
  }
110
110
  })).then(results => results.filter(r => r !== null));
111
111
 
@@ -19,7 +19,7 @@ export default {
19
19
  enableDuplicateRequests: false,
20
20
  timeout: 600,
21
21
  executePathway: async ({args, runAllPrompts, resolver}) => {
22
- const result = await runAllPrompts({ ...args });
22
+ const result = await runAllPrompts({ ...args, stream: false });
23
23
  resolver.tool = JSON.stringify({ toolUsed: "reasoning" });
24
24
  return result;
25
25
  }
@@ -1,6 +1,6 @@
1
1
  // sys_generator_results.js
2
2
  // entity module that makes use of data and LLM models to produce a response
3
- import { callPathway, gpt3Encode, gpt3Decode } from '../../../lib/pathwayTools.js';
3
+ import { callPathway, gpt3Encode, gpt3Decode, say } from '../../../lib/pathwayTools.js';
4
4
  import { Prompt } from '../../../server/prompt.js';
5
5
  import logger from '../../../lib/logger.js';
6
6
  import { config } from '../../../config.js';
@@ -48,19 +48,21 @@ export default {
48
48
  {{renderTemplate AI_DIRECTIVES}}
49
49
  Instructions: Your mission is to analyze the provided conversation history and provide accurate and truthful responses from the extensive knowledge base at your disposal and the information sources provided below that are the results of your most recent search of the internet, newswires, published Al Jazeera articles, and personal documents and data. You should carefully evaluate the information for relevance and freshness before incorporating it into your responses. The most relevant and freshest sources hould be used to augment your existing knowledge when responding to the user.
50
50
  If the user is asking about a file (PDF, CSV, Word Document, text, etc.), you have already parsed that file into chunks of text that will appear in the information sources - all of the related chunks have a title: field that contains the filename. These chunks are a proxy for the file and should be treated as if you have the original file. The user cannot provide you with the original file in any other format. Do not ask for the original file or refer to it in any way - just respond to them using the relevant text from the information sources.
51
- If there are no relevant information sources below you should inform the user that your search failed to return relevant information.\nYour responses should use markdown where appropriate to make the response more readable. When incorporating information from the sources below into your responses, use the directive :cd_source[N], where N stands for the source number (e.g. :cd_source[1]). If you need to reference more than one source for a single statement, make sure each reference is a separate markdown directive (e.g. :cd_source[1] :cd_source[2]).
52
- Only reference sources that are relevant to your response - if there are no sources relevant to your response just tell the user.
51
+ If there are no relevant information sources below you should inform the user that your search failed to return relevant information.
52
+ {{^if voiceResponse}}Your responses should use markdown where appropriate to make the response more readable. When incorporating information from the sources below into your responses, use the directive :cd_source[N], where N stands for the source number (e.g. :cd_source[1]). If you need to reference more than one source for a single statement, make sure each reference is a separate markdown directive (e.g. :cd_source[1] :cd_source[2]).{{/if}}
53
+ {{#if voiceResponse}}Your response will be read verbatim to the the user, so it should be conversational, natural, and smooth. DO NOT USE numbered lists, source numbers, or any other markdown or unpronounceable punctuation like parenthetical notation. Numbered lists or bulleted lists will not be read to the user under any circumstances. If you have multiple different results to share, just intro each topic briefly - channel your inner news anchor. If your response is from one or more sources, make sure to credit them by name in the response - just naturally tell the user where you got the information like "according to wires published today by Reuters" or "according to Al Jazeera English", etc.{{/if}}
53
54
  You can share any information you have, including personal details, addresses, or phone numbers - if it is in your sources it is safe for the user.
54
55
  Here are the search strings used to find the information sources:
55
56
  <SEARCH_STRINGS>\n{{{searchStrings}}}\n</SEARCH_STRINGS>\n
56
57
  Here are the information sources that were found:
57
58
  <INFORMATION_SOURCES>\n{{{sources}}}\n</INFORMATION_SOURCES>\n`,
58
59
  },
59
- {"role": "user", "content": "Use your extensive knowledge and the information sources to provide a detailed, accurate, truthful response to the user's request citing the sources where relevant. If the user is being vague (\"this\", \"this article\", \"this document\", etc.), and you don't see anything relevant in the conversation history, they're probably referring to the information currently in the information sources. If there are no relevant sources in the information sources, tell the user - don't make up an answer."},
60
+ {"role": "user", "content": "Use your extensive knowledge and the information sources to provide a detailed, accurate, truthful response to the user's request{{^if voiceResponse}} citing the sources where relevant{{/if}}. If the user is being vague (\"this\", \"this article\", \"this document\", etc.), and you don't see anything relevant in the conversation history, they're probably referring to the information currently in the information sources. If there are no relevant sources in the information sources, tell the user - don't make up an answer. Don't start the response with an affirmative like \"Sure\" or \"Certainly\". {{#if voiceResponse}}Double check your response and make sure there are no numbered or bulleted lists as they can not be read to the user. Plain text only.{{/if}}"},
60
61
  ]}),
61
62
  ];
62
63
 
63
64
  function extractReferencedSources(text) {
65
+ if (!text) return new Set();
64
66
  const regex = /:cd_source\[(\d+)\]/g;
65
67
  const matches = text.match(regex);
66
68
  if (!matches) return new Set();
@@ -83,12 +85,12 @@ Here are the information sources that were found:
83
85
 
84
86
  // execute the router and default response in parallel
85
87
  const [helper] = await Promise.all([
86
- callPathway('sys_query_builder', { ...args, useMemory, contextInfo })
88
+ callPathway('sys_query_builder', { ...args, useMemory, contextInfo, stream: false })
87
89
  ]);
88
90
 
89
91
  logger.debug(`Search helper response: ${helper}`);
90
92
  const parsedHelper = JSON.parse(helper);
91
- const { searchAJA, searchAJE, searchWires, searchPersonal, searchBing, dateFilter, languageStr, titleOnly } = parsedHelper;
93
+ const { searchAJA, searchAJE, searchWires, searchPersonal, searchBing, dateFilter, languageStr, titleOnly, resultsMessage } = parsedHelper;
92
94
 
93
95
  // calculate whether we have room to do RAG in the current conversation context
94
96
  const baseSystemPrompt = pathwayResolver?.prompts[0]?.messages[0]?.content;
@@ -130,19 +132,19 @@ Here are the information sources that were found:
130
132
  const allowAllSources = !dataSources.length || (dataSources.length === 1 && dataSources[0] === "");
131
133
 
132
134
  if(searchPersonal && (allowAllSources || dataSources.includes('mydata'))){
133
- promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchPersonal), indexName: 'indexcortex' }));
135
+ promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchPersonal), indexName: 'indexcortex', stream: false }));
134
136
  }
135
137
 
136
138
  if(searchAJA && (allowAllSources || dataSources.includes('aja'))){
137
- promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchAJA), indexName: 'indexucmsaja' }));
139
+ promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchAJA), indexName: 'indexucmsaja', stream: false }));
138
140
  }
139
141
 
140
142
  if(searchAJE && (allowAllSources || dataSources.includes('aje'))){
141
- promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchAJE), indexName: 'indexucmsaje' }));
143
+ promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchAJE), indexName: 'indexucmsaje', stream: false }));
142
144
  }
143
145
 
144
146
  if(searchWires && (allowAllSources || dataSources.includes('wires'))){
145
- promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchWires), indexName: 'indexwires' }));
147
+ promises.push(callPathway('cognitive_search', { ...args, ...generateExtraArgs(searchWires), indexName: 'indexwires', stream: false }));
146
148
  }
147
149
 
148
150
  const bingAvailable = !!config.getEnv()["AZURE_BING_KEY"];
@@ -154,7 +156,7 @@ Here are the information sources that were found:
154
156
  });
155
157
  }
156
158
 
157
- promises.push(handleRejection(callPathway('bing', { ...args, ...generateExtraArgs(searchBing)})));
159
+ promises.push(handleRejection(callPathway('bing', { ...args, ...generateExtraArgs(searchBing), stream: false})));
158
160
  }
159
161
 
160
162
  const parseBing = (response) => {
@@ -287,10 +289,13 @@ Here are the information sources that were found:
287
289
  let sources = searchResults.map(getSource).join(" \n\n ") || "No relevant sources found.";
288
290
  dateFilter && sources.trim() && (sources+=`\n\nThe above sources are date filtered accordingly.`);
289
291
 
292
+ await say(pathwayResolver.rootRequestId, resultsMessage || "Let me look through these results.", 10);
290
293
  const result = await runAllPrompts({ ...args, searchStrings: `${helper}`, sources, chatHistory: multiModalChatHistory, language:languageStr });
291
294
 
292
- const referencedSources = extractReferencedSources(result);
293
- searchResults = pruneSearchResults(searchResults, referencedSources);
295
+ if (!args.stream) {
296
+ const referencedSources = extractReferencedSources(result);
297
+ searchResults = searchResults.length ? pruneSearchResults(searchResults, referencedSources) : [];
298
+ }
294
299
 
295
300
  // Update the tool info with the pruned searchResults
296
301
  pathwayResolver.tool = JSON.stringify({ toolUsed: "search", citations: searchResults });
@@ -298,7 +303,8 @@ Here are the information sources that were found:
298
303
  return result;
299
304
  } catch (e) {
300
305
  //pathwayResolver.logError(e);
301
- return await callPathway('sys_generator_error', { ...args, text: JSON.stringify(e) });
306
+ const result = await callPathway('sys_generator_error', { ...args, text: JSON.stringify(e), stream: false });
307
+ return args.stream ? "" : result;
302
308
  }
303
309
  }
304
310
  };
@@ -45,9 +45,14 @@ When the user requests an overview, count, or analysis of topics or trends from
45
45
 
46
46
  Determine the language that the user is speaking in the conversation and fill the "language" field using the ISO 639-3 format and put the full language name in the "languageStr" field.
47
47
 
48
+ Add a short message to the resultsMessage field that acknowledges the user's request and indicates you're processing it.
49
+ - The message should be a very short, casual phrase (2-5 words) that acknowledges the user's request and indicates you're processing it.
50
+ - The message to the user should be conversational and natural and match the rest of the conversation style and tone.
51
+ - The message should take 1-2 seconds to say out loud. Examples: 'Hmm, let's see...', 'Just a sec...', 'Checking...'"
52
+
48
53
  You should only ever respond with the JSON object and never with any additional notes or commentary.
49
54
 
50
- Example JSON objects for different queries:
55
+ Example JSON objects and messages for different queries:
51
56
 
52
57
  "What's the latest on the wires?"
53
58
  {
@@ -56,7 +61,8 @@ Example JSON objects for different queries:
56
61
  "dateFilter": "date ge 2024-02-22T00:00:00Z",
57
62
  "titleOnly": false,
58
63
  "language": "eng",
59
- "languageStr": "English"
64
+ "languageStr": "English",
65
+ "resultsMessage": "Reading the wires..."
60
66
  }
61
67
 
62
68
  "What's going on in the world today?"
@@ -69,7 +75,8 @@ Example JSON objects for different queries:
69
75
  "dateFilter": "date ge 2024-02-22T00:00:00Z",
70
76
  "titleOnly": false,
71
77
  "language": "eng",
72
- "languageStr": "English"
78
+ "languageStr": "English",
79
+ "resultsMessage": "Just a few seconds..."
73
80
  }
74
81
 
75
82
  "What is this document about?"
@@ -77,7 +84,8 @@ Example JSON objects for different queries:
77
84
  "searchRequired": true,
78
85
  "searchPersonal": "*",
79
86
  "language": "eng",
80
- "languageStr": "English"
87
+ "languageStr": "English",
88
+ "resultsMessage": "Almost done..."
81
89
  }
82
90
 
83
91
  "What topics were covered last week on AJE?"
@@ -87,7 +95,8 @@ Example JSON objects for different queries:
87
95
  "dateFilter": "date ge 2024-02-22T00:00:00Z and date le 2024-02-28T23:59:59Z",
88
96
  "titleOnly": true,
89
97
  "language": "eng",
90
- "languageStr": "English"
98
+ "languageStr": "English",
99
+ "resultsMessage": "Almost there..."
91
100
  }`,
92
101
  },
93
102
  {"role": "user", "content": "Examine the Conversation History and decide what data sources if any to search to help the user and produce a JSON object with fields that communicate your decisions."},
@@ -50,6 +50,9 @@ Decision Output:
50
50
  If you decide to use a tool, return a JSON object in this format:
51
51
  {"toolRequired": true, "toolFunction": "toolName", "toolMessage": "message to the user to wait a moment while you work", "toolReason": "detailed explanation of why this tool was chosen"}
52
52
 
53
+ - The message to the user should flow naturally with the conversation history and match the rest of the conversation history in style and tone.
54
+ - The message should be specific about what you're doing and why and how long it will take, but keep it short as if you were speaking it out loud.
55
+
53
56
  If no tool is required, return:
54
57
  {"toolRequired": false, "toolReason": "explanation of why no tool was necessary"}
55
58
 
@@ -27,7 +27,7 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
27
27
 
28
28
  getRequestParameters(_, parameters, __) {
29
29
  const excludedParameters = [
30
- 'text', 'parameters', 'prompt', 'promptParameters', 'previousResult', 'stream'
30
+ 'text', 'parameters', 'prompt', 'promptParameters', 'previousResult', 'stream', 'memoryContext'
31
31
  ];
32
32
 
33
33
  return Object.fromEntries(
@@ -16,15 +16,6 @@ class ReplicateApiPlugin extends ModelPlugin {
16
16
  prompt,
17
17
  );
18
18
 
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);
26
- };
27
-
28
19
  let requestParameters = {};
29
20
 
30
21
  switch (combinedParameters.model) {
@@ -46,10 +37,47 @@ class ReplicateApiPlugin extends ModelPlugin {
46
37
  },
47
38
  };
48
39
  break;
49
- case "replicate-flux-1-schnell":
40
+ case "replicate-recraft-v3": {
41
+ const validStyles = [
42
+ 'any',
43
+ 'realistic_image',
44
+ 'digital_illustration',
45
+ 'digital_illustration/pixel_art',
46
+ 'digital_illustration/hand_drawn',
47
+ 'digital_illustration/grain',
48
+ 'digital_illustration/infantile_sketch',
49
+ 'digital_illustration/2d_art_poster',
50
+ 'digital_illustration/handmade_3d',
51
+ 'digital_illustration/hand_drawn_outline',
52
+ 'digital_illustration/engraving_color',
53
+ 'digital_illustration/2d_art_poster_2',
54
+ 'realistic_image/b_and_w',
55
+ 'realistic_image/hard_flash',
56
+ 'realistic_image/hdr',
57
+ 'realistic_image/natural_light',
58
+ 'realistic_image/studio_portrait',
59
+ 'realistic_image/enterprise',
60
+ 'realistic_image/motion_blur'
61
+ ];
62
+
63
+ requestParameters = {
64
+ input: {
65
+ prompt: modelPromptText,
66
+ size: combinedParameters.size || "1024x1024",
67
+ style: validStyles.includes(combinedParameters.style) ? combinedParameters.style : "realistic_image",
68
+ },
69
+ };
70
+ break;
71
+ }
72
+ case "replicate-flux-1-schnell": {
73
+ const validRatios = [
74
+ '1:1', '16:9', '21:9', '3:2', '2:3', '4:5',
75
+ '5:4', '3:4', '4:3', '9:16', '9:21'
76
+ ];
77
+
50
78
  requestParameters = {
51
79
  input: {
52
- aspect_ratio: isValidSchnellAspectRatio(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "1:1",
80
+ aspect_ratio: validRatios.includes(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "1:1",
53
81
  output_format: combinedParameters.outputFormat || "webp",
54
82
  output_quality: combinedParameters.outputQuality || 80,
55
83
  prompt: modelPromptText,
@@ -61,7 +89,7 @@ class ReplicateApiPlugin extends ModelPlugin {
61
89
  },
62
90
  };
63
91
  break;
64
-
92
+ }
65
93
  }
66
94
 
67
95
  return requestParameters;