@aj-archipelago/cortex 1.3.31 → 1.3.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex-file-handler",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "File handling service for Cortex - handles file uploads, media chunking, and document processing",
5
5
  "type": "module",
6
6
  "scripts": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aj-archipelago/cortex",
3
- "version": "1.3.31",
3
+ "version": "1.3.32",
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": {
@@ -33,7 +33,7 @@
33
33
  "type": "module",
34
34
  "homepage": "https://github.com/aj-archipelago/cortex#readme",
35
35
  "dependencies": {
36
- "@aj-archipelago/subvibe": "^1.0.8",
36
+ "@aj-archipelago/subvibe": "^1.0.10",
37
37
  "@apollo/server": "^4.7.3",
38
38
  "@apollo/server-plugin-response-cache": "^4.1.2",
39
39
  "@apollo/utils.keyvadapter": "^3.0.0",
@@ -9,7 +9,7 @@ export default {
9
9
  height: 1024,
10
10
  aspectRatio: "custom",
11
11
  numberResults: 1,
12
- safety_tolerance: 5,
12
+ safety_tolerance: 6,
13
13
  output_format: "webp",
14
14
  output_quality: 80,
15
15
  steps: 4,
@@ -139,6 +139,14 @@ const addToolResults = (chatHistory, result, toolCallId) => {
139
139
  return { chatHistory, toolCallId };
140
140
  };
141
141
 
142
+ const insertToolCallAndResults = (chatHistory, toolArgs, toolName, result = null, toolCallId = getUniqueId()) => {
143
+ const lastMessage = chatHistory.length > 0 ? chatHistory.pop() : null;
144
+ addToolCalls(chatHistory, toolArgs, toolName, toolCallId);
145
+ addToolResults(chatHistory, result, toolCallId);
146
+ chatHistory.push(lastMessage);
147
+ return { chatHistory, toolCallId };
148
+ };
149
+
142
150
  const modifyText = (text, modifications) => {
143
151
  let modifiedText = text || '';
144
152
 
@@ -225,4 +233,4 @@ const modifyText = (text, modifications) => {
225
233
  return modifiedText;
226
234
  };
227
235
 
228
- export { normalizeMemoryFormat, enforceTokenLimit, addToolCalls, addToolResults, modifyText };
236
+ export { normalizeMemoryFormat, enforceTokenLimit, addToolCalls, addToolResults, modifyText, insertToolCallAndResults };
@@ -5,7 +5,7 @@ import logger from '../../../lib/logger.js';
5
5
  import { chatArgsHasImageUrl } from '../../../lib/util.js';
6
6
  import { QueueServiceClient } from '@azure/storage-queue';
7
7
  import { config } from '../../../config.js';
8
- import { addToolCalls, addToolResults } from './memory/shared/sys_memory_helpers.js';
8
+ import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
9
9
 
10
10
  const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
11
11
  let queueClient;
@@ -94,13 +94,10 @@ export default {
94
94
  if (args.chatHistory.length > 1) {
95
95
  const memoryContext = await callPathway('sys_read_memory', { ...args, section: 'memoryContext', priority: 0, recentHours: 0, stream: false }, pathwayResolver);
96
96
  if (memoryContext) {
97
- const lastMessage = args.chatHistory.length > 0 ? args.chatHistory.pop() : null;
98
- const { toolCallId } = addToolCalls(args.chatHistory, "search memory for relevant information", "memory_lookup");
99
- addToolResults(args.chatHistory, memoryContext, toolCallId);
100
- args.chatHistory.push(lastMessage);
97
+ insertToolCallAndResults(args.chatHistory, "search memory for relevant information", "memory_lookup", memoryContext);
101
98
  }
102
99
  }
103
-
100
+
104
101
  // If we're using voice, get a quick response to say
105
102
  let ackResponse = null;
106
103
  if (args.voiceResponse) {
@@ -222,7 +219,7 @@ export default {
222
219
  title = await fetchTitleResponsePromise;
223
220
 
224
221
  pathwayResolver.tool = JSON.stringify({
225
- hideFromModel: toolCallbackName ? true : false,
222
+ hideFromModel: (!args.stream && toolCallbackName) ? true : false,
226
223
  toolCallbackName,
227
224
  title,
228
225
  search: toolCallbackName === 'sys_generator_results' ? true : false,
@@ -3,7 +3,7 @@
3
3
  import { callPathway } from '../../../lib/pathwayTools.js';
4
4
  import { Prompt } from '../../../server/prompt.js';
5
5
  import logger from '../../../lib/logger.js';
6
- import { addToolCalls, addToolResults } from './memory/shared/sys_memory_helpers.js';
6
+ import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
7
7
 
8
8
  export default {
9
9
  prompt: [],
@@ -73,8 +73,7 @@ Instructions: As part of a conversation with the user, you have been asked to cr
73
73
 
74
74
  // add the tool_calls and tool_results to the chatHistory
75
75
  imageResults.forEach((imageResult, index) => {
76
- const { toolCallId } = addToolCalls(chatHistory, imagePrompts[index], "generate_image");
77
- addToolResults(chatHistory, imageResult, toolCallId, "generate_image");
76
+ insertToolCallAndResults(chatHistory, imagePrompts[index], "generate_image", imageResult);
78
77
  });
79
78
 
80
79
  const result = await runAllPrompts({ ...args });
@@ -1,5 +1,5 @@
1
1
  import { callPathway } from '../../../lib/pathwayTools.js';
2
- import { addToolCalls, addToolResults } from './memory/shared/sys_memory_helpers.js';
2
+ import { insertToolCallAndResults } from './memory/shared/sys_memory_helpers.js';
3
3
 
4
4
  export default {
5
5
  prompt:
@@ -20,8 +20,7 @@ export default {
20
20
 
21
21
  const memoryContext = await callPathway('sys_search_memory', { ...args, stream: false, section: 'memoryAll', updateContext: true });
22
22
  if (memoryContext) {
23
- const {toolCallId} = addToolCalls(args.chatHistory, "search memory for relevant information", "memory_lookup");
24
- addToolResults(args.chatHistory, memoryContext, toolCallId);
23
+ insertToolCallAndResults(args.chatHistory, "search memory for relevant information", "memory_lookup", memoryContext);
25
24
  }
26
25
 
27
26
  let result;
@@ -15,7 +15,7 @@ export default {
15
15
  let pathwayResolver = resolver;
16
16
 
17
17
  const promptMessages = [
18
- {"role": "system", "content": `{{renderTemplate AI_MEMORY}}\n\n{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n{{renderTemplate AI_EXPERTISE}} While you have those capabilities but you have already decided it is not necessary to do any of those things to respond in this turn of the conversation. Never pretend like you are searching, looking anything up, or reading or looking in a file or show the user any made up or hallucinated information including non-existent images.\n{{renderTemplate AI_MEMORY_INSTRUCTIONS}}\n{{renderTemplate AI_DATETIME}}`},
18
+ {"role": "system", "content": `{{renderTemplate AI_MEMORY}}\n\n{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n{{renderTemplate AI_EXPERTISE}}\n{{renderTemplate AI_MEMORY_INSTRUCTIONS}}\n{{renderTemplate AI_DATETIME}}`},
19
19
  "{{chatHistory}}",
20
20
  ];
21
21
 
@@ -56,8 +56,16 @@ If you decide to use a tool, return a JSON object in this format:
56
56
 
57
57
  toolMessage Guidelines:
58
58
  - The message should be consistent in style and tone with the rest of your responses in the conversation history.
59
- - The message should be brief and conversational and flow naturally with the conversation history.
60
- - The message should be something a human would say to the user to stall for time while you're working on the task.
59
+ - The message should be brief, conversational, and flow naturally with the conversation history.
60
+ - Use contractions (I'm, don't, let's) and informal language to sound more natural.
61
+ - Include slight verbal hesitations or false starts occasionally (e.g., "So... I think what we could do here is" or "Actually, let me try a different approach").
62
+ - Vary sentence length and structure - mix short punchy sentences with longer ones.
63
+ - Include casual transitions and filler phrases that humans use: "you know," "basically," "so," "actually," "by the way," "anyway," etc.
64
+ - Express uncertainty when appropriate with phrases like "I'm pretty sure," "If I remember correctly," or "I think."
65
+ - Reference personal preferences or opinions occasionally ("I personally find that..." or "I tend to prefer...").
66
+ - Occasionally make minor self-corrections as humans do ("Wait, let me rephrase that" or "Actually, I meant to say...").
67
+ - Humans don't refer to tools - stall for time by saying things like "Let me think about this for a sec," "Drawing that up for you now," or "Working on it..." Humans also stall with vocalizations like "hmm," "let's see," or "give me a moment."
68
+ - When appropriate, react emotionally to content with expressions like "Wow!" or "That's interesting!"
61
69
 
62
70
  If no tool is required, return:
63
71
  {"toolRequired": false, "toolReason": "explanation of why no tool was necessary"}
@@ -5,7 +5,6 @@ import { Prompt } from "../server/prompt.js";
5
5
 
6
6
  const OFFSET_CHUNK = 500; //seconds of each chunk offset, only used if helper does not provide
7
7
 
8
- // Function to properly detect YouTube URLs
9
8
  function isYoutubeUrl(url) {
10
9
  try {
11
10
  const urlObj = new URL(url);
@@ -23,6 +22,10 @@ function isYoutubeUrl(url) {
23
22
  if (urlObj.pathname.startsWith("/embed/")) {
24
23
  return urlObj.pathname.length > 7; // '/embed/' is 7 chars
25
24
  }
25
+ // For shorts URLs, verify they have a video ID in the path
26
+ if (urlObj.pathname.startsWith("/shorts/")) {
27
+ return urlObj.pathname.length > 8; // '/shorts/' is 8 chars
28
+ }
26
29
  return false;
27
30
  }
28
31
 
@@ -45,7 +48,7 @@ export default {
45
48
  "{{messages}}",
46
49
  ]}),
47
50
  ],
48
- model: 'gemini-flash-20-vision',
51
+ model: 'gemini-pro-20-vision',
49
52
  inputParameters: {
50
53
  file: ``,
51
54
  language: ``,
@@ -96,7 +99,10 @@ export default {
96
99
  sendProgress(true);
97
100
  intervalId = setInterval(() => sendProgress(true), 3000);
98
101
 
99
- const { file, responseFormat, wordTimestamped, maxLineWidth } = args;
102
+ const { file, wordTimestamped, maxLineWidth } = args;
103
+
104
+ const responseFormat = args.responseFormat || 'text';
105
+
100
106
  if(!file) {
101
107
  throw new Error("Please provide a file to transcribe.");
102
108
  }
@@ -129,9 +135,7 @@ export default {
129
135
  respectLimitsPrompt += ` These subtitles will be shown in a ${possiblePlacement} formatted video player. Each subtitle line should not exceed ${maxLineWidth} characters to fit the player.`;
130
136
  }
131
137
 
132
- function getMessages(file, format) {
133
-
134
- const responseFormat = format !== 'text' ? 'VTT' : 'text';
138
+ function getMessages(file) {
135
139
 
136
140
  // Base system content that's always included
137
141
  let systemContent = `Instructions:
@@ -216,7 +220,7 @@ REMEMBER:
216
220
  const messages = [
217
221
  {"role": "system", "content": systemContent},
218
222
  {"role": "user", "content": [
219
- `{ type: 'text', text: 'Transcribe this file in ${responseFormat} format.${respectLimitsPrompt}' }`,
223
+ `{ type: 'text', text: 'Transcribe this file in ${responseFormat} format.${respectLimitsPrompt} Output only the transcription, no other text or comments or formatting.' }`,
220
224
  JSON.stringify({
221
225
  type: 'image_url',
222
226
  url: file,
@@ -266,7 +270,7 @@ REMEMBER:
266
270
 
267
271
  const result = await processChunksParallel(chunks, args);
268
272
 
269
- if (['srt','vtt'].includes(responseFormat) || wordTimestamped) { // align subtitles for formats
273
+ if (['srt','vtt'].includes(responseFormat.toLowerCase()) || wordTimestamped) { // align subtitles for formats
270
274
  const offsets = chunks.map((chunk, index) => chunk?.offset || index * OFFSET_CHUNK);
271
275
  return alignSubtitles(result, responseFormat, offsets);
272
276
  }