`- URL: ${url}`, `- Title: ${title}`, `- Description: ${description}`, ] : [`No active browser tab.`]; const content = [ `Below are some real-time context details you can use to inform your response:`, `Locale: ${locale}`, `Timezone: ${timezone}`, `Current date & time in ISO format: ${isoTimestamp}`, `Today's date: ${datePart || "Unavailable"}`, ``, ...tabSection, ].join("\n"); return { role: "system", content, }; } /** * Constructs the relevant memories context message to be inejcted before the user message. * * @param {string} message User message to find relevant memories for * @returns {Promise} Relevant memories context message or null if no relevant memories */ export async function constructRelevantMemoriesContextMessage(message) { const relevantMemories = await lazy.MemoriesManager.getRelevantMemories(message); // If there are relevant memories, render and return the context message if (relevantMemories.length) { const relevantMemoriesList = "- " + relevantMemories .map(memory => { return memory.memory_summary; }) .join("\n- "); const content = await lazy.renderPrompt( lazy.relevantMemoriesContextPrompt, { relevantMemoriesList, } ); return { role: "system", content, }; } // If there aren't any relevant memories, return null return null; } /** * Response parsing funtions to detect special tagged information like memories and search terms. * Also return the cleaned content after removing all the taggings. * * @param {string} content * @returns {Promise} */ export async function parseContentWithTokens(content) { const searchRegex = /§search:\s*([^§]+)§/gi; const memoriesRegex = /§existing_memory:\s*([^§]+)§/gi; const searchTokens = detectTokens(content, searchRegex, "query"); const memoriesTokens = detectTokens(content, memoriesRegex, "memories"); // Sort all tokens in reverse index order for easier removal const allTokens = [...searchTokens, ...memoriesTokens].sort( (a, b) => b.startIndex - a.startIndex ); if (allTokens.length === 0) { return { cleanContent: content, searchQueries: [], usedMemories: [], }; } // Clean content by removing tagged information let cleanContent = content; const searchQueries = []; const usedMemories = []; for (const token of allTokens) { if (token.query) { searchQueries.unshift(token.query); } else if (token.memories) { usedMemories.unshift(token.memories); // TODO: do we need customEvent to dispatch used memories as we iterate? } cleanContent = cleanContent.slice(0, token.startIndex) + cleanContent.slice(token.endIndex); } return { cleanContent: cleanContent.trim(), searchQueries, usedMemories, }; } /** * Given the content and the regex pattern to search, find all occurrence of matches. * * @param {string} content * @param {RegExp} regexPattern * @param {string} key * @returns {Array} */ export function detectTokens(content, regexPattern, key) { const matches = []; let match; while ((match = regexPattern.exec(content)) !== null) { matches.push({ fullMatch: match[0], [key]: match[1].trim(), startIndex: match.index, endIndex: match.index + match[0].length, }); } return matches; } PK