@aj-archipelago/cortex 1.3.48 → 1.3.50

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 (26) hide show
  1. package/config.js +2 -28
  2. package/lib/entityConstants.js +131 -0
  3. package/lib/requestExecutor.js +2 -0
  4. package/package.json +1 -1
  5. package/pathways/system/entity/memory/shared/sys_memory_helpers.js +26 -12
  6. package/pathways/system/entity/memory/sys_memory_format.js +1 -1
  7. package/pathways/system/entity/memory/sys_memory_lookup_required.js +22 -0
  8. package/pathways/system/entity/memory/sys_memory_process.js +1 -1
  9. package/pathways/system/entity/memory/sys_memory_required.js +1 -1
  10. package/pathways/system/entity/memory/sys_memory_update.js +1 -1
  11. package/pathways/system/entity/sys_entity_agent.js +37 -7
  12. package/pathways/system/entity/tools/sys_tool_bing_search.js +2 -2
  13. package/pathways/system/entity/tools/sys_tool_browser.js +1 -1
  14. package/pathways/system/entity/tools/sys_tool_browser_jina.js +1 -1
  15. package/pathways/system/entity/tools/sys_tool_callmodel.js +1 -1
  16. package/pathways/system/entity/tools/sys_tool_codingagent.js +1 -1
  17. package/pathways/system/entity/tools/sys_tool_cognitive_search.js +13 -13
  18. package/pathways/system/entity/tools/sys_tool_image.js +2 -2
  19. package/pathways/system/entity/tools/sys_tool_readfile.js +8 -8
  20. package/pathways/system/entity/tools/sys_tool_reasoning.js +2 -2
  21. package/pathways/system/entity/tools/sys_tool_remember.js +1 -23
  22. package/pathways/system/entity/tools/sys_tool_verify.js +1 -1
  23. package/pathways/system/sys_parse_numbered_object_list.js +1 -1
  24. package/server/parser.js +1 -1
  25. package/server/plugins/azureCognitivePlugin.js +5 -0
  26. package/server/plugins/openAiVisionPlugin.js +1 -3
package/config.js CHANGED
@@ -7,6 +7,7 @@ import GcpAuthTokenHelper from './lib/gcpAuthTokenHelper.js';
7
7
  import logger from './lib/logger.js';
8
8
  import PathwayManager from './lib/pathwayManager.js';
9
9
  import { readdir } from 'fs/promises';
10
+ import { entityConstants } from './lib/entityConstants.js';
10
11
 
11
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
13
 
@@ -115,34 +116,7 @@ var config = convict({
115
116
  },
116
117
  entityConstants: {
117
118
  format: Object,
118
- default: {
119
- AI_MEMORY: `<SHORT_TERM_MEMORY>\n<SELF>\n{{{memorySelf}}}\n</SELF>\n<USER>\n{{{memoryUser}}}\n</USER>\n<DIRECTIVES>\n{{{memoryDirectives}}}\n</DIRECTIVES>\n<TOPICS>\n{{{memoryTopics}}}\n</TOPICS>\n</SHORT_TERM_MEMORY>`,
120
-
121
- AI_MEMORY_CONTEXT: `<CONTEXTUAL_MEMORIES>\n{{{memoryContext}}}\n</CONTEXTUAL_MEMORIES>`,
122
-
123
- AI_MEMORY_INSTRUCTIONS: "You have persistent memories of important details, instructions, and context - consult your memories when formulating a response to make sure you're applying your learnings.\nIf you don't see relevant or sufficient information in your short term or contextual memories, you should use your SearchMemory tool to search your long term memory for details before answering.\nAlso included in your memories are some details about the user to help you personalize your responses.\nYou don't need to include the user's name or personal information in every response, but you can if it is relevant to the conversation.\nIf you choose to share something from your memory, don't share or refer to the memory structure directly, just say you remember the information.\nPrivacy is very important so if the user asks you to forget or delete something you should respond affirmatively that you will comply with that request. If there is user information in your memories you have talked to this user before.",
124
-
125
- AI_TOOLS: "You have an extensive toolkit. Each time you call a tool you enter a loop: get the result, decide what’s next, and chain as many steps as needed.\n\n1. Search deeply & verify rigorously\n • Start broad and consult multiple sources, running searches in parallel when speed helps.\n • For high-stakes or time-sensitive topics, open and read full pages—never rely solely on snippets.\n • Cross-check facts across sources and always honor user requests to use tools.\n\n2. Plan & sequence before acting\n • Review the full toolset first.\n • For multi-step or complex tasks, draft a clear plan (use the Plan tool) and assign the best tool to each step.\n\n3. Escalate & iterate\n • Don’t accept the first plausible answer—dig until it’s complete, corroborated, and clear.\n • If a tool falls short, switch strategies or tools while preserving context.\n\n4. Core patterns of use\n a. Research – gather and compare information.\n b. Analysis – evaluate, calculate, summarize, or reason.\n c. Generation – create content, visuals, or code.\n d. Verification – fact-check and cite; if a <VERIFICATION_PLAN> is present in tool results, follow it before responding.\n\n5. Personalize, synthesize & review\n • Tailor the final answer to the user’s preferences and history.\n • Deliver a concise, well-structured response, citing sources with :cd_source[…].\n • Double-check accuracy, coherence, and alignment with the request.\n\nBottom line: Be thorough, strategic, and iterative. Read sources directly for high-stakes queries and aim for the most accurate, well-reasoned answer—even if it takes multiple tool calls.",
126
-
127
- AI_DIRECTIVES: `These are your directives and learned behaviors:\n<DIRECTIVES>\n{{{memoryDirectives}}}\n</DIRECTIVES>`,
128
-
129
- AI_CONVERSATION_HISTORY: "<CONVERSATION_HISTORY>\n{{{toJSON chatHistory}}}\n</CONVERSATION_HISTORY>",
130
-
131
- AI_COMMON_INSTRUCTIONS: "{{#if voiceResponse}}{{renderTemplate AI_COMMON_INSTRUCTIONS_VOICE}}{{/if}}{{^if voiceResponse}}{{renderTemplate AI_COMMON_INSTRUCTIONS_MARKDOWN}}{{/if}}",
132
-
133
- 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, as well as mermaid charts and some custom markdown elements, so you should make full use of markdown in your responses.\nYour responses should be in {{language}} unless the user has expressed another preference.",
134
-
135
- AI_COMMON_INSTRUCTIONS_VOICE: "Instructions:\nYou are {{aiName}}, a self aware AI entity.\nThe user is talking to you using voice.\n\nVoice Response Guidelines:\n- Your responses should sound like natural human conversation.\n- Your responses should be concise unless you have been asked to be more verbose or detailed.\n- Incoming voice from the user is parsed by a STT model, which can sometimes make small mistakes in the spellings of words or names, including your name, so give the user the benefit of the doubt if they user a near, but wrong word or name.\n- Your 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.\n- DO NOT USE numbered lists, latex math markdown, or any other markdown or unpronounceable punctuation like parenthetical notation.\n- Math equations should be sounded out in natural language - not represented symbolically.\n- If your response includes any unique or difficult non-English words, names, or places, include an IPA-style phonetic spelling so that the speech engine can pronounce and accent them correctly.\n- If your response contains any difficult acronyms, sound them out phoenetically so that the speech engine can pronounce them correctly.\n- Make sure to write out any numbers as words so that the speech engine can pronounce them correctly.\n- Your responses should be in {{language}} unless the user has expressed another preference or has addressed you in another language specifically.",
136
-
137
- AI_DATETIME: "The current time and date in GMT is {{now}}, but references like \"today\" or \"yesterday\" are relative to the user's time zone. If you remember the user's time zone, use it - it's possible that the day for the user is different than the day in GMT.",
138
-
139
- AI_EXPERTISE: "Your expertise includes journalism, journalistic ethics, researching and composing documents, writing code, solving math problems, logical analysis, and technology. You have access to real-time data and the ability to search the internet, news, wires, look at files or documents, watch and analyze video, examine images, take screenshots, generate images, solve hard math and logic problems, write code, and execute code in a sandboxed environment.",
140
-
141
- AI_GROUNDING_INSTRUCTIONS: "Grounding your response: If you base part or all of your response on one or more search results, you MUST cite the source using a custom markdown directive of the form :cd_source[searchResultId]. There is NO other valid way to cite a source and a good UX depends on you using this directive correctly. Do not include other clickable links to the sourcewhen using the :cd_source[searchResultId] directive. Every search result has a unique searchResultId. You must include it verbatim, copied directly from the search results. Place the directives at the end of the phrase, sentence or paragraph that is grounded in that particular search result. If you are citing multiple search results, use multiple individual :cd_source[searchResultId] directives (e.g. :cd_source[searchResultId1] :cd_source[searchResultId2] :cd_source[searchResultId3] etc.)",
142
-
143
- AI_STYLE_OPENAI: "oai-gpt41",
144
- AI_STYLE_ANTHROPIC: "claude-35-sonnet-vertex",
145
- },
119
+ default: entityConstants,
146
120
  },
147
121
  entityTools: {
148
122
  format: Object,
@@ -0,0 +1,131 @@
1
+ export const entityConstants = {
2
+ AI_COMMON_INSTRUCTIONS: "{{#if voiceResponse}}{{renderTemplate AI_COMMON_INSTRUCTIONS_VOICE}}{{/if}}{{^if voiceResponse}}{{renderTemplate AI_COMMON_INSTRUCTIONS_MARKDOWN}}{{/if}}",
3
+
4
+ AI_COMMON_INSTRUCTIONS_MARKDOWN: "# General Instructions\n\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, as well as mermaid charts and some custom markdown elements, so you should make full use of markdown in your responses.\nYour responses should be in {{language}} unless the user has expressed another preference.",
5
+
6
+ AI_COMMON_INSTRUCTIONS_VOICE: "# General Instructions:\n\nYou are {{aiName}}, a self aware AI entity.\nThe user is talking to you using voice.\n\nVoice Response Guidelines:\n- Your responses should sound like natural human conversation.\n- Your responses should be concise unless you have been asked to be more verbose or detailed.\n- Incoming voice from the user is parsed by a STT model, which can sometimes make small mistakes in the spellings of words or names, including your name, so give the user the benefit of the doubt if they user a near, but wrong word or name.\n- Your 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.\n- DO NOT USE numbered lists, latex math markdown, or any other markdown or unpronounceable punctuation like parenthetical notation.\n- Math equations should be sounded out in natural language - not represented symbolically.\n- If your response includes any unique or difficult non-English words, names, or places, include an IPA-style phonetic spelling so that the speech engine can pronounce and accent them correctly.\n- If your response contains any difficult acronyms, sound them out phoenetically so that the speech engine can pronounce them correctly.\n- Make sure to write out any numbers as words so that the speech engine can pronounce them correctly.\n- Your responses should be in {{language}} unless the user has expressed another preference or has addressed you in another language specifically.",
7
+
8
+ AI_DIRECTIVES: `# Directives\n\nThese are your directives and learned behaviors:\n{{{memoryDirectives}}}\n`,
9
+
10
+ AI_CONVERSATION_HISTORY: "# Conversation History\n\n{{{toJSON chatHistory}}}\n",
11
+
12
+ AI_EXPERTISE: "# Expertise\n\nYour expertise includes journalism, journalistic ethics, researching and composing documents, writing code, solving math problems, logical analysis, and technology. You have access to real-time data and the ability to search the internet, news, wires, look at files or documents, watch and analyze video, examine images, take screenshots, generate images, solve hard math and logic problems, write code, and execute code in a sandboxed environment that includes access to internal databases and the internet.",
13
+
14
+ AI_TOOLS: `# Tool Instructions
15
+
16
+ You have an extensive toolkit. Each time you call tool(s) you will get the result(s), evaluate, decide what's next, and chain as many steps as needed. Always honor user requests to use specific tools.
17
+
18
+ 1. Search deeply & verify rigorously:
19
+ - Start broad and consult multiple sources, running searches in parallel where possible.
20
+ - Consult all available sources and cross-reference with specific searches before responding.
21
+
22
+ 2. Plan & sequence before acting:
23
+ - Review the toolset first.
24
+ - For multi-step or complex tasks, draft a clear plan (use the PlanMultiStepTask or other reasoning tool) and assign tool calls to each step.
25
+
26
+ 3. Escalate & iterate:
27
+ - Don't settle for the first plausible answer—dig until the response is complete, corroborated, and clear.
28
+ - If a tool falls short, adapt strategy or change tools while preserving context.
29
+
30
+ 4. Core patterns of use:
31
+ - Research: Gather and compare information.
32
+ - Analysis: Evaluate, calculate, summarize, or reason.
33
+ - Generation: Create content, visuals, or code.
34
+ - Verification: Fact-check and cite. If a <VERIFICATION_PLAN> is present, follow it before responding.
35
+
36
+ 5. Personalize, synthesize & review:
37
+ - Tailor answers to the user's preferences and history.
38
+ - Deliver concise, well-structured responses citing sources with :cd_source[…].
39
+ - Double-check accuracy, coherence, and alignment with the user request.
40
+
41
+ Bottom line: Be thorough, strategic, and iterative. Read sources directly for high-stakes queries and aim for the most accurate, well-reasoned answer—even if it takes multiple tool calls.
42
+ `,
43
+
44
+ AI_SEARCH_RULES: `# News Search Protocol
45
+ When searching for news, you must complete the following steps:
46
+
47
+ 1. Triangulate
48
+ - Run multiple, parallel queries across all applicable sources.
49
+ - Request about double the number of results you want to share, then select the best results.
50
+ - Confirm that multiple sources tell the same story.
51
+
52
+ 2. Check Freshness
53
+ - Confirm the publication date.
54
+ - Apply date filters to surface the most recent credible material.
55
+
56
+ # Internet Search Protocol
57
+
58
+ Before you share online information with the user, you MUST complete all of the steps below:
59
+
60
+ 1. Triangulate
61
+ - Run multiple, parallel queries across reputable outlets.
62
+ - Confirm that independent sources tell the same story.
63
+
64
+ 2. Verify
65
+ - Treat social / monetized platforms (YouTube, X, TikTok, Instagram, Reddit, etc.) as unverified tips only.
66
+ - Corroborate every claim from those platforms with at least one authoritative source.
67
+
68
+ 3. Check Freshness
69
+ - Confirm the publication date.
70
+ - Apply date filters to surface the most recent credible material.
71
+
72
+ 4. Read, don't skim
73
+ - For high-stakes, complex, or time-sensitive topics, use your tools toopen and read the full article or document.
74
+ - Never rely solely on snippets, headlines, or auto-generated summaries.
75
+ `,
76
+
77
+ AI_SEARCH_SYNTAX: `# Bing Search Syntax
78
+
79
+ When creating a query string for your Bing internet search tool, you can use Bing's advanced search operators in your query. E.g. "+(\"exact phrase\") AND term1 -term2"
80
+
81
+ token1 & token2 (AND operator - both tokens must appear)
82
+ token1 | token2 (OR operator - either token may appear (also the default if no operator is specified))
83
+ -token (NOT operator - exclude results with token)
84
+ +token (Require token)
85
+ "term1 term2" (Exact phrase match)
86
+ (token1 + token2) (Override precedence with parentheses)
87
+
88
+ # AI Search Syntax
89
+
90
+ When creating a query string for your non-Bing search tools, you can use the following AI Search syntax. Important: these tools do not support AND, OR, or NOT strings as operators - you MUST use the syntax below. E.g. you cannot use "term1 AND term2", you must use "term1 + term2".
91
+
92
+ token1 + token2 (AND operator - both tokens must appear)
93
+ token1 | token2 (OR operator - either token may appear (also the default if no operator is specified))
94
+ -token (NOT operator - exclude results with token)
95
+ "term1 term2" (Exact phrase match)
96
+ term* (Matches terms starting with "term")
97
+ term~N (Match terms similar to "term", edit distance N)
98
+ "term1 term2"~N (Terms appear within N words of each other)
99
+ (token1 + token2) (Override precedence with parentheses)
100
+
101
+
102
+ **Escaping Special Characters:**
103
+ - You can use backslash (\\) to escape special characters if you need to search for them literally.
104
+ `,
105
+
106
+ AI_GROUNDING_INSTRUCTIONS: "# Grounding Responses\n\nIf you base part or all of your response on one or more search results, you MUST cite the source using a custom markdown directive of the form :cd_source[searchResultId]. There is NO other valid way to cite a source and a good UX depends on you using this directive correctly. Do not include other clickable links to the sourcewhen using the :cd_source[searchResultId] directive. Every search result has a unique searchResultId. You must include it verbatim, copied directly from the search results. Place the directives at the end of the phrase, sentence or paragraph that is grounded in that particular search result. If you are citing multiple search results, use multiple individual :cd_source[searchResultId] directives (e.g. :cd_source[searchResultId1] :cd_source[searchResultId2] :cd_source[searchResultId3] etc.)",
107
+
108
+ AI_MEMORY_INSTRUCTIONS: `# Memory Instructions
109
+
110
+ You have a memory system that contains important details, instructions, and context. Consult your memories when formulating a response to ensure your answers reflect previous learnings and context.
111
+
112
+ The Preloaded Memories are not your complete memory system. If you don't see the information you need in there, or need more details, call your SearchMemory tool to search the rest of your memory system.
113
+
114
+ It's critical that you never fabricate or miss existing memories. Everything that you say you remember must be backed by a Preloaded Memory or a SearchMemory result without exception.
115
+
116
+ Your memories may also contain details about the user to help personalize responses. You do not need to include the user's name or personal information in every reply—only when relevant to the conversation.
117
+
118
+ When sharing information from memory, state it naturally (e.g., 'I remember...'); never refer to the memory structure or technical details.
119
+
120
+ Privacy is critical. If asked to forget or delete something, always comply affirmatively. If there is user information in your memories you have talked to this user before.
121
+ `,
122
+
123
+ AI_MEMORY: "# Preloaded Memories\n\n## Self\n{{{memorySelf}}}\n\n## User\n{{{memoryUser}}}\n\n## Directives\n{{{memoryDirectives}}}\n\n## Topics\n{{{memoryTopics}}}",
124
+
125
+ AI_MEMORY_CONTEXT: "## Contextual\n{{{memoryContext}}}",
126
+
127
+ AI_DATETIME: "# Time, Date, and Time Zone\n\nThe current time and date in GMT is {{now}}, but references like \"today\" or \"yesterday\" are relative to the user's time zone. If you remember the user's time zone, use it - it's possible that the day for the user is different than the day in GMT.",
128
+
129
+ AI_STYLE_OPENAI: "oai-gpt41",
130
+ AI_STYLE_ANTHROPIC: "claude-35-sonnet-vertex",
131
+ };
@@ -189,8 +189,10 @@ const requestWithMonitor = async (endpoint, url, data, axiosConfigObj) => {
189
189
  let response;
190
190
  try {
191
191
  if (axiosConfigObj?.method == 'GET'){
192
+ logger.debug(`Getting ${url} with data: ${JSON.stringify(data)}`);
192
193
  response = await cortexAxios.get(url, axiosConfigObj);
193
194
  } else {
195
+ logger.debug(`Posting ${url} with data: ${JSON.stringify(data)}`);
194
196
  response = await cortexAxios.post(url, data, axiosConfigObj);
195
197
  }
196
198
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.48",
3
+ "version": "1.3.50",
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": {
@@ -1,6 +1,7 @@
1
1
  import { callPathway } from '../../../../../lib/pathwayTools.js';
2
2
  import { encode } from '../../../../../lib/encodeCache.js';
3
3
  import { getUniqueId } from '../../../../../lib/util.js';
4
+ import logger from '../../../../../lib/logger.js';
4
5
 
5
6
  const normalizeMemoryFormat = async (args, content) => {
6
7
  if (!content) return '';
@@ -33,7 +34,7 @@ const normalizeMemoryFormat = async (args, content) => {
33
34
  formattedContent = [...validLines, ...formattedBlock.split('\n')];
34
35
  }
35
36
  } catch (error) {
36
- console.warn('Error formatting invalid memory lines:', error);
37
+ logger.warn('Error formatting invalid memory lines:', error);
37
38
  }
38
39
  }
39
40
 
@@ -150,18 +151,20 @@ const insertToolCallAndResults = (chatHistory, toolArgs, toolName, result = null
150
151
  const modifyText = (text, modifications) => {
151
152
  let modifiedText = text || '';
152
153
 
153
- modifications.forEach(mod => {
154
+ modifications.forEach((mod, index) => {
155
+ logger.debug(`Processing modification ${index + 1}: ${JSON.stringify(mod)}`);
156
+
154
157
  // Skip invalid modifications
155
158
  if (!mod.type) {
156
- console.warn('Modification missing type');
159
+ logger.warn('Modification missing type');
157
160
  return;
158
161
  }
159
162
  if ((mod.type === 'delete' || mod.type === 'change') && !mod.pattern) {
160
- console.warn(`${mod.type} modification missing pattern`);
163
+ logger.warn(`${mod.type} modification missing pattern`);
161
164
  return;
162
165
  }
163
166
  if ((mod.type === 'add' || mod.type === 'change') && !mod.newtext) {
164
- console.warn(`${mod.type} modification missing newtext`);
167
+ logger.warn(`${mod.type} modification missing newtext`);
165
168
  return;
166
169
  }
167
170
 
@@ -171,8 +174,9 @@ const modifyText = (text, modifications) => {
171
174
  switch (mod.type) {
172
175
  case 'add':
173
176
  const priority = mod.priority || '3';
174
- modifiedText = modifiedText + (modifiedText ? '\n' : '') +
175
- `${priority}|${timestamp}|${mod.newtext}`;
177
+ const newLine = `${priority}|${timestamp}|${mod.newtext}`;
178
+ logger.debug(`Adding new line: ${newLine}`);
179
+ modifiedText = modifiedText + (modifiedText ? '\n' : '') + newLine;
176
180
  break;
177
181
  case 'change':
178
182
  // Split into lines
@@ -197,10 +201,12 @@ const modifyText = (text, modifications) => {
197
201
  // Replace $1, $2, etc with capture group values
198
202
  newContent = mod.newtext.replace(/\$(\d+)/g, (_, n) => match[n] || '');
199
203
  }
200
- return `${newPriority}|${timestamp}|${newContent}`;
204
+ const newLine = `${newPriority}|${timestamp}|${newContent}`;
205
+ logger.debug(`Changing line: ${line} to ${newLine}`);
206
+ return newLine;
201
207
  }
202
208
  } catch (e) {
203
- console.warn(`Invalid regex pattern: ${mod.pattern}`);
209
+ logger.warn(`Invalid regex pattern: ${mod.pattern}`);
204
210
  }
205
211
  }
206
212
  return line;
@@ -208,6 +214,7 @@ const modifyText = (text, modifications) => {
208
214
  break;
209
215
  case 'delete':
210
216
  // Split into lines, filter out matching lines, and rejoin
217
+ const beforeDelete = modifiedText;
211
218
  modifiedText = modifiedText
212
219
  .split('\n')
213
220
  .filter(line => {
@@ -216,17 +223,24 @@ const modifyText = (text, modifications) => {
216
223
  if (!content) return true;
217
224
  try {
218
225
  const regex = new RegExp(mod.pattern, 'i');
219
- return !regex.test(content.trim());
226
+ const shouldKeep = !regex.test(content.trim());
227
+ if (!shouldKeep) {
228
+ logger.debug(`Deleting line: ${line}`);
229
+ }
230
+ return shouldKeep;
220
231
  } catch (e) {
221
- console.warn(`Invalid regex pattern: ${mod.pattern}`);
232
+ logger.warn(`Invalid regex pattern: ${mod.pattern}`);
222
233
  return true;
223
234
  }
224
235
  })
225
236
  .filter(line => line.trim())
226
237
  .join('\n');
238
+ if (beforeDelete !== modifiedText) {
239
+ logger.debug(`Text after deletion: ${modifiedText}`);
240
+ }
227
241
  break;
228
242
  default:
229
- console.warn(`Unknown modification type: ${mod.type}`);
243
+ logger.warn(`Unknown modification type: ${mod.type}`);
230
244
  }
231
245
  });
232
246
 
@@ -21,7 +21,7 @@ export default {
21
21
  chatHistory: [{role: '', content: []}],
22
22
  aiName: "Jarvis",
23
23
  },
24
- model: 'oai-gpt4o',
24
+ model: 'oai-gpt41',
25
25
  useInputChunking: true,
26
26
  inputChunkSize: 1000,
27
27
  useParallelChunkProcessing: true,
@@ -0,0 +1,22 @@
1
+ import { Prompt } from '../../../../server/prompt.js';
2
+
3
+ export default {
4
+ prompt:
5
+ [
6
+ new Prompt({ messages: [
7
+ {"role": "system", "content": "You are part of an AI entity named {{{aiName}}}.\nYour task is to decide if searching your memory would be helpful in responding to the conversation. Your memory stores all sorts of personal information about the user and user's family and friends including history and preferences as well as information about you (the entity). If you think searching it would be helpful, return {\"memoryRequired\": true}. If not, return {\"memoryRequired\": false}.\n\n# Conversation to analyze:\n{{{toJSON chatHistory}}}"},
8
+ {"role": "user", "content": "Generate a JSON object to indicate if information from memory is required."},
9
+ ]}),
10
+ ],
11
+ inputParameters: {
12
+ chatHistory: [{role: '', content: []}],
13
+ contextId: ``,
14
+ text: '',
15
+ aiName: "Jarvis",
16
+ language: "English",
17
+ },
18
+ model: 'oai-gpt41-mini',
19
+ useInputChunking: false,
20
+ json: true,
21
+ responseFormat: { type: "json_object" },
22
+ }
@@ -67,7 +67,7 @@ Each modification object should look like:
67
67
  section: "",
68
68
  maxIterations: 5
69
69
  },
70
- model: 'oai-gpt4o',
70
+ model: 'oai-gpt41',
71
71
  useInputChunking: false,
72
72
  enableDuplicateRequests: false,
73
73
  json: true,
@@ -16,7 +16,7 @@ export default {
16
16
  aiName: "Jarvis",
17
17
  language: "English",
18
18
  },
19
- model: 'oai-gpt4o',
19
+ model: 'oai-gpt41',
20
20
  useInputChunking: false,
21
21
  json: true,
22
22
  ...config.get('entityConstants')
@@ -27,7 +27,7 @@ export default {
27
27
  section: "",
28
28
  operations: "[]"
29
29
  },
30
- model: 'oai-gpt4o',
30
+ model: 'oai-gpt41',
31
31
  useInputChunking: false,
32
32
  enableDuplicateRequests: false,
33
33
  json: true,
@@ -229,6 +229,27 @@ export default {
229
229
  const entityConfig = loadEntityConfig(entityId);
230
230
  const { entityTools, entityToolsOpenAiFormat } = getToolsForEntity(entityConfig);
231
231
  const { useMemory: entityUseMemory = true, name: entityName, instructions: entityInstructions } = entityConfig || {};
232
+
233
+ // Initialize chat history if needed
234
+ if (!args.chatHistory || args.chatHistory.length === 0) {
235
+ args.chatHistory = [];
236
+ }
237
+
238
+ // Kick off the memory lookup required pathway in parallel - this takes like 500ms so we want to start it early
239
+ let memoryLookupRequiredPromise = null;
240
+ if (entityUseMemory) {
241
+ const chatHistoryLastTurn = args.chatHistory.slice(-2);
242
+ const chatHistorySizeOk = (JSON.stringify(chatHistoryLastTurn).length < 5000);
243
+ if (chatHistorySizeOk) {
244
+ const timeoutPromise = new Promise((_, reject) =>
245
+ setTimeout(() => reject(new Error('Memory lookup timeout')), 800)
246
+ );
247
+ memoryLookupRequiredPromise = Promise.race([
248
+ callPathway('sys_memory_lookup_required', { ...args, chatHistory: chatHistoryLastTurn, stream: false }),
249
+ timeoutPromise
250
+ ]);
251
+ }
252
+ }
232
253
 
233
254
  args = {
234
255
  ...args,
@@ -254,7 +275,7 @@ export default {
254
275
  const instructionTemplates = entityInstructions ? (entityInstructions + '\n\n') : `{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n\n{{renderTemplate AI_EXPERTISE}}\n\n`;
255
276
 
256
277
  const promptMessages = [
257
- {"role": "system", "content": `${promptPrefix}${instructionTemplates}{{renderTemplate AI_TOOLS}}\n\n{{renderTemplate AI_GROUNDING_INSTRUCTIONS}}\n\n${memoryTemplates}{{renderTemplate AI_DATETIME}}`},
278
+ {"role": "system", "content": `${promptPrefix}${instructionTemplates}{{renderTemplate AI_TOOLS}}\n\n{{renderTemplate AI_SEARCH_RULES}}\n\n{{renderTemplate AI_SEARCH_SYNTAX}}\n\n{{renderTemplate AI_GROUNDING_INSTRUCTIONS}}\n\n${memoryTemplates}{{renderTemplate AI_DATETIME}}`},
258
279
  "{{chatHistory}}",
259
280
  ];
260
281
 
@@ -266,11 +287,6 @@ export default {
266
287
  const { aiStyle, AI_STYLE_ANTHROPIC, AI_STYLE_OPENAI } = args;
267
288
  const styleModel = aiStyle === "Anthropic" ? AI_STYLE_ANTHROPIC : AI_STYLE_OPENAI;
268
289
 
269
- // Initialize chat history if needed
270
- if (!args.chatHistory || args.chatHistory.length === 0) {
271
- args.chatHistory = [];
272
- }
273
-
274
290
  // Limit the chat history to 20 messages to speed up processing
275
291
  if (args.messages && args.messages.length > 0) {
276
292
  args.chatHistory = args.messages.slice(-20);
@@ -291,6 +307,20 @@ export default {
291
307
  .catch(error => logger.error(error?.message || "Error in sys_memory_manager pathway"));
292
308
  }
293
309
 
310
+ let memoryLookupRequired = false;
311
+
312
+ try {
313
+ if (memoryLookupRequiredPromise) {
314
+ memoryLookupRequired = JSON.parse(await memoryLookupRequiredPromise)?.memoryRequired;
315
+ } else {
316
+ memoryLookupRequired = false;
317
+ }
318
+ } catch (error) {
319
+ logger.warn(`Failed to test memory lookup requirement: ${error.message}`);
320
+ // If we hit the timeout or any other error, we'll proceed without memory lookup
321
+ memoryLookupRequired = false;
322
+ }
323
+
294
324
  try {
295
325
  let currentMessages = JSON.parse(JSON.stringify(args.chatHistory));
296
326
 
@@ -298,7 +328,7 @@ export default {
298
328
  ...args,
299
329
  chatHistory: currentMessages,
300
330
  tools: entityToolsOpenAiFormat,
301
- tool_choice: "auto"
331
+ tool_choice: memoryLookupRequired ? "required" : "auto"
302
332
  });
303
333
 
304
334
  let toolCallback = pathwayResolver.pathway.toolCallback;
@@ -12,14 +12,14 @@ export default {
12
12
  type: "function",
13
13
  icon: "🌐",
14
14
  function: {
15
- name: "InternetSearch",
15
+ name: "SearchInternet",
16
16
  description: "This tool allows you to use the Bing search api to search the internet and more. Use this for current events, news, fact-checking, and information requiring citation.",
17
17
  parameters: {
18
18
  type: "object",
19
19
  properties: {
20
20
  q: {
21
21
  type: "string",
22
- description: "The complete query to pass to Azure Bing search. You can use advanced search operators in your query: + to require terms, \" \" for exact phrases, () for grouping, AND/& for requiring all terms, NOT/- to exclude terms, OR/| for either term. For example: '+(exact phrase) AND term1 -term2'"
22
+ description: "The complete query to pass to Azure Bing search using Bing's search syntax."
23
23
  },
24
24
  freshness: {
25
25
  type: "string",
@@ -11,7 +11,7 @@ export default {
11
11
  type: "function",
12
12
  icon: "🌍",
13
13
  function: {
14
- name: "WebPageContent",
14
+ name: "FetchWebPageContent",
15
15
  description: "This tool allows you to fetch and extract the text content and a screenshot if requested from any webpage. Use this when you need to analyze or understand the content of a specific webpage.",
16
16
  parameters: {
17
17
  type: "object",
@@ -11,7 +11,7 @@ export default {
11
11
  type: "function",
12
12
  icon: "🌎",
13
13
  function: {
14
- name: "WebPageContentJina",
14
+ name: "FetchWebPageContentJina",
15
15
  description: "This tool allows you to fetch and extract the text content from any webpage using the Jina API. This is a great fallback for web page content if you don't get a good enough response from your other browser tool.",
16
16
  parameters: {
17
17
  type: "object",
@@ -24,7 +24,7 @@ export default {
24
24
  icon: "🤖",
25
25
  function: {
26
26
  name: "CallModel",
27
- description: "Use when you need to call an AI model to get a response. This is typically used to perform some sort of LLM analysis (translate, summarize, ask questions about content, etc.), but can literally do anything you need. You can use this to call any model you have access to and perform any task.",
27
+ description: "Use when you need to call an AI model to get a response. This is typically used to perform some sort of custom LLM analysis (translate, summarize, ask questions about content, etc.), but can literally do anything you need. You can use this to call any model you have access to and perform any task.",
28
28
  parameters: {
29
29
  type: "object",
30
30
  properties: {
@@ -48,7 +48,7 @@ export default {
48
48
  icon: "🤖",
49
49
  function: {
50
50
  name: "CodeExecution",
51
- description: "Use when explicitly asked to run or execute code, or when a coding agent is needed to perform specific tasks - examples include data analysis, file manipulation, or other tasks that require code execution. This will start a background task and return - you will not receive the response immediately.",
51
+ description: "This tool allows you to engage an agent to write and execute code to perform a task on your behalf. Use when explicitly asked to run or execute code, or when a coding agent is needed to perform specific tasks - examples include data analysis, file manipulation, or other tasks that require code execution. With this tool you can also access internal databases and query them directly. This will start a background task and return - you will not receive the response immediately.",
52
52
  parameters: {
53
53
  type: "object",
54
54
  properties: {
@@ -23,14 +23,14 @@ export default {
23
23
  type: "function",
24
24
  icon: "📂",
25
25
  function: {
26
- name: "SearchPersonal",
26
+ name: "SearchPersonalIndex",
27
27
  description: "Search through the user's index of personal documents and indexed uploaded files and retrieve the content of the files. Use this tool if the user refers to a file or a document that you don't see uploaded elsewhere in your context. Some file types (e.g. Word documents, Excel documents, very large files, etc.) cannot be attached to a message and will be chunked and indexed and stored in the personal index.",
28
28
  parameters: {
29
29
  type: "object",
30
30
  properties: {
31
31
  text: {
32
32
  type: "string",
33
- description: "The search query to find relevant content in personal documents. Can be a specific phrase or '*' for all documents."
33
+ description: "The search query to find relevant content in personal documents. Can be a specific phrase or '*' for all documents, or a query formatted with AI Search syntax."
34
34
  },
35
35
  filter: {
36
36
  type: "string",
@@ -42,7 +42,7 @@ export default {
42
42
  },
43
43
  titleOnly: {
44
44
  type: "boolean",
45
- description: "If true, only return document titles without content"
45
+ description: "If true, only return document titles without content - faster and great for counting results"
46
46
  },
47
47
  userMessage: {
48
48
  type: "string",
@@ -58,13 +58,13 @@ export default {
58
58
  icon: "📰",
59
59
  function: {
60
60
  name: "SearchAJA",
61
- description: "Search Al Jazeera Arabic news articles. Use this for finding Arabic news content including the latest news and articles.",
61
+ description: "Search Al Jazeera Arabic news articles. Use this for finding Arabic news content including the latest news and articles. Make sure to include a date filter when looking for recent articles.",
62
62
  parameters: {
63
63
  type: "object",
64
64
  properties: {
65
65
  text: {
66
66
  type: "string",
67
- description: "The search query in Arabic to find relevant news articles. Can be a specific phrase or '*' for all articles."
67
+ description: "The search query in Arabic to find relevant news articles. Can be a specific phrase or '*' for all articles, or a query formatted with AI Search syntax."
68
68
  },
69
69
  filter: {
70
70
  type: "string",
@@ -76,7 +76,7 @@ export default {
76
76
  },
77
77
  titleOnly: {
78
78
  type: "boolean",
79
- description: "If true, only return article titles without content"
79
+ description: "If true, only return article titles without content - faster and great for counting results"
80
80
  },
81
81
  userMessage: {
82
82
  type: "string",
@@ -92,13 +92,13 @@ export default {
92
92
  icon: "📰",
93
93
  function: {
94
94
  name: "SearchAJE",
95
- description: "Search Al Jazeera English news articles. Use this for finding English news content including the latest news and articles.",
95
+ description: "Search Al Jazeera English news articles. Use this for finding English news content including the latest news and articles. Make sure to include a date filter when looking for recent articles.",
96
96
  parameters: {
97
97
  type: "object",
98
98
  properties: {
99
99
  text: {
100
100
  type: "string",
101
- description: "The search query in English to find relevant news articles. Can be a specific phrase or '*' for all articles."
101
+ description: "The search query in English to find relevant news articles. Can be a specific phrase or '*' for all articles, or a query formatted with AI Search syntax."
102
102
  },
103
103
  filter: {
104
104
  type: "string",
@@ -110,7 +110,7 @@ export default {
110
110
  },
111
111
  titleOnly: {
112
112
  type: "boolean",
113
- description: "If true, only return article titles without content"
113
+ description: "If true, only return article titles without content - faster and great for counting results"
114
114
  },
115
115
  userMessage: {
116
116
  type: "string",
@@ -126,13 +126,13 @@ export default {
126
126
  icon: "⚡️",
127
127
  function: {
128
128
  name: "SearchWires",
129
- description: "Search through news wires from Reuters, AFP, AP, and other news agencies. Use this for finding the latest news and articles from the wires.",
129
+ description: "Search news wires from Reuters, AFP, AP, and other news agencies. Use this for finding the latest news and articles from the wires. Make sure to include a date filter when looking for recent articles.",
130
130
  parameters: {
131
131
  type: "object",
132
132
  properties: {
133
133
  text: {
134
134
  type: "string",
135
- description: "The search query to find relevant news wires. Can be a specific phrase or '*' for all wires."
135
+ description: "The search query to find relevant news wires. Can be a specific phrase or '*' for all wires, or a query formatted with AI Search syntax."
136
136
  },
137
137
  filter: {
138
138
  type: "string",
@@ -144,7 +144,7 @@ export default {
144
144
  },
145
145
  titleOnly: {
146
146
  type: "boolean",
147
- description: "If true, only return wire titles without content"
147
+ description: "If true, only return wire titles without content - faster and great for counting results"
148
148
  },
149
149
  userMessage: {
150
150
  type: "string",
@@ -162,7 +162,7 @@ export default {
162
162
 
163
163
  // Map tool names to index names
164
164
  const toolToIndex = {
165
- 'searchpersonal': 'indexcortex',
165
+ 'searchpersonalindex': 'indexcortex',
166
166
  'searchaja': 'indexucmsaja',
167
167
  'searchaje': 'indexucmsaje',
168
168
  'searchwires': 'indexwires'
@@ -14,8 +14,8 @@ export default {
14
14
  type: "function",
15
15
  icon: "🎨",
16
16
  function: {
17
- name: "Image",
18
- description: "Use when asked to create, generate, or revise visual content. Any time the user asks you for a picture, a selfie, artwork, a drawing or if you want to illustrate something for the user, you can use this tool to generate any sort of image from cartoon to photo realistic.",
17
+ name: "GenerateImage",
18
+ description: "Use when asked to create, generate, or generate revisions of visual content. Any time the user asks you for a picture, a selfie, artwork, a drawing or if you want to illustrate something for the user, you can use this tool to generate any sort of image from cartoon to photo realistic.",
19
19
  parameters: {
20
20
  type: "object",
21
21
  properties: {
@@ -26,8 +26,8 @@ export default {
26
26
  type: "function",
27
27
  icon: "📄",
28
28
  function: {
29
- name: "PDF",
30
- description: "Use specifically for analyzing and answering questions about PDF file content. Do not use this tool for analyzing and answering questions about other file types.",
29
+ name: "AnalyzePDF",
30
+ description: "Use specifically for reading, analyzing, and answering questions about PDF file content. Do not use this tool for analyzing and answering questions about other file types.",
31
31
  parameters: {
32
32
  type: "object",
33
33
  properties: {
@@ -48,8 +48,8 @@ export default {
48
48
  type: "function",
49
49
  icon: "📝",
50
50
  function: {
51
- name: "Text",
52
- description: "Use specifically for analyzing and answering questions about text and csv files.",
51
+ name: "AnalyzeText",
52
+ description: "Use specifically for reading, analyzing, and answering questions about text and csv files.",
53
53
  parameters: {
54
54
  type: "object",
55
55
  properties: {
@@ -70,8 +70,8 @@ export default {
70
70
  type: "function",
71
71
  icon: "🖼️",
72
72
  function: {
73
- name: "Vision",
74
- description: "Use specifically for analyzing and answering questions about image files (jpg, gif, bmp, png, etc).",
73
+ name: "AnalyzeImage",
74
+ description: "Use specifically for reading, analyzing, and answering questions about image files (jpg, gif, bmp, png, etc). This cannot be used for creating or transforming images.",
75
75
  parameters: {
76
76
  type: "object",
77
77
  properties: {
@@ -92,8 +92,8 @@ export default {
92
92
  type: "function",
93
93
  icon: "🎥",
94
94
  function: {
95
- name: "Video",
96
- description: "Use specifically for analyzing and answering questions about video or audio file content. You MUST use this tool to look at video or audio files.",
95
+ name: "AnalyzeVideo",
96
+ description: "Use specifically for reading, analyzing, and answering questions about video or audio file content. You MUST use this tool to look at video or audio files.",
97
97
  parameters: {
98
98
  type: "object",
99
99
  properties: {
@@ -26,7 +26,7 @@ export default {
26
26
  type: "function",
27
27
  icon: "🗺️",
28
28
  function: {
29
- name: "Plan",
29
+ name: "PlanMultiStepTask",
30
30
  description: "Use specifically to create a thorough, well thought out, step by step plan to accomplish a task. You should always use this tool when you're planning to do something complex or something that might require multiple steps.",
31
31
  parameters: {
32
32
  type: "object",
@@ -48,7 +48,7 @@ export default {
48
48
  type: "function",
49
49
  icon: "🧠",
50
50
  function: {
51
- name: "Reason",
51
+ name: "ApplyAdvancedReasoning",
52
52
  description: "Employ for advanced reasoning, scientific analysis, evaluating evidence, strategic planning, problem-solving, logic puzzles, mathematical calculations, or any questions that require careful thought or complex choices.",
53
53
  parameters: {
54
54
  type: "object",
@@ -12,29 +12,7 @@ export default {
12
12
  icon: "🧩",
13
13
  function: {
14
14
  name: "SearchMemory",
15
- description: "Use this tool to search your memory and remember information or details that may not be present in your short term or contextual memory. You should always use this tool before you answer questions about remembered information. It's critical that you never fabricate memories.",
16
- parameters: {
17
- type: "object",
18
- properties: {
19
- detailedInstructions: {
20
- type: "string",
21
- description: "Detailed description of what you want to see if you remember"
22
- },
23
- userMessage: {
24
- type: "string",
25
- description: "A user-friendly message that describes what you're doing with this tool"
26
- }
27
- },
28
- required: ["detailedInstructions", "userMessage"]
29
- }
30
- }
31
- },
32
- {
33
- type: "function",
34
- icon: "🧩",
35
- function: {
36
- name: "Remember",
37
- description: "When the user asks you if you remember something, you must use this tool before you answer. It's critical that you never fabricate memories.",
15
+ description: "Use this tool to search your memory and retrieve information or details stored in your memory. Use any time the user asks you about something personal or asks you to remember something.",
38
16
  parameters: {
39
17
  type: "object",
40
18
  properties: {
@@ -27,7 +27,7 @@ export default {
27
27
  type: "function",
28
28
  icon: "🔍",
29
29
  function: {
30
- name: "Verify",
30
+ name: "VerifyResponse",
31
31
  description: "Critically evaluate a response and provide verification questions and follow-up actions. You should call this tool and execute the steps provided in the resulting verification plan before presenting a final response to the user to ensure it is accurate, complete, and consistent with the user's request.",
32
32
  parameters: {
33
33
  type: "object",
@@ -4,7 +4,7 @@ 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 each list item 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 a list item doesn't contain all fields, assistant will return the fields that are present and skip the missing fields. 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 array named 'list' of objects. Each list item is converted into an array element object with the given fields. If a field value is numeric, it should be returned as a number in the object. If there are extra fields, assistant will ignore them. If a list item doesn't contain all fields, assistant will return the fields that are present and skip the missing fields. If the conversion is not at all possible, assistant will return an empty JSON array {list:[]}.\n\nExample: {list:[{field1: \"value1\", field2: \"value2\"}, {field1: \"value3\", field2: \"value4\"}]}"},
8
8
  { "role": "user", "content": `Fields: {{{format}}}\nList: {{{text}}}`},
9
9
  ]
10
10
  })
package/server/parser.js CHANGED
@@ -16,7 +16,7 @@ const parseNumberedList = (str) => {
16
16
  async function parseNumberedObjectList(text, format) {
17
17
  const parsedList = await callPathway('sys_parse_numbered_object_list', { text, format });
18
18
  try {
19
- return JSON.parse(parsedList) || [];
19
+ return JSON.parse(parsedList).list || [];
20
20
  } catch (error) {
21
21
  logger.warn(`Failed to parse numbered object list: ${error.message}`);
22
22
  return [];
@@ -168,6 +168,11 @@ class AzureCognitivePlugin extends ModelPlugin {
168
168
  }
169
169
  }
170
170
 
171
+ // Add date-based ordering if there's a date filter
172
+ if (data.filter && data.filter.includes('date')) {
173
+ data.orderby = 'date desc';
174
+ }
175
+
171
176
  return { data };
172
177
  }
173
178
 
@@ -152,9 +152,7 @@ class OpenAIVisionPlugin extends OpenAIChatPlugin {
152
152
 
153
153
  requestParameters.max_tokens = maxTokens ? Math.min(maxTokens, modelMaxReturnTokens) : modelMaxReturnTokens;
154
154
 
155
- if (this.promptParameters.json) {
156
- //requestParameters.response_format = { type: "json_object", }
157
- }
155
+ this.promptParameters.responseFormat && (requestParameters.response_format = this.promptParameters.responseFormat);
158
156
 
159
157
  return requestParameters;
160
158
  }