const pluralize = require("pluralize"); const { WorkspaceAgentInvocation, } = require("../../models/workspaceAgentInvocation"); const { writeResponseChunk } = require("../helpers/chat/responses"); const { Workspace } = require("../../models/workspace"); /** * In-memory cache for attachments associated with agent invocations. * Attachments are stored here when grepAgents creates an invocation, * then retrieved by AgentHandler when the websocket connects. * @type {Map} */ const invocationAttachmentsCache = new Map(); /** * Store attachments for an invocation UUID * @param {string} uuid - The invocation UUID * @param {Array} attachments - The attachments array */ function cacheInvocationAttachments(uuid, attachments = []) { if (attachments.length > 0) { invocationAttachmentsCache.set(uuid, attachments); } } /** * Retrieve and remove attachments for an invocation UUID * @param {string} uuid - The invocation UUID * @returns {Array} The attachments array (empty if none cached) */ function getAndClearInvocationAttachments(uuid) { const attachments = invocationAttachmentsCache.get(uuid) || []; invocationAttachmentsCache.delete(uuid); return attachments; } async function grepAgents({ uuid, response, message, workspace, user = null, thread = null, attachments = [], }) { let nativeToolingEnabled = false; // If the workspace is in automatic mode, check if the workspace supports native tooling // to determine if the agent flow should be used or not. if (workspace?.chatMode === "automatic") nativeToolingEnabled = await Workspace.supportsNativeToolCalling(workspace); const agentHandles = WorkspaceAgentInvocation.parseAgents(message); if (agentHandles.length > 0 || nativeToolingEnabled) { const { invocation: newInvocation } = await WorkspaceAgentInvocation.new({ prompt: message, workspace: workspace, user: user, thread: thread, }); if (!newInvocation) { writeResponseChunk(response, { id: uuid, type: "statusResponse", textResponse: `${pluralize( "Agent", agentHandles.length )} ${agentHandles.join( ", " )} could not be called. Chat will be handled as default chat.`, sources: [], close: true, animate: false, error: null, }); return; } // Cache attachments for the websocket handler to retrieve later cacheInvocationAttachments(newInvocation.uuid, attachments); writeResponseChunk(response, { id: uuid, type: "agentInitWebsocketConnection", textResponse: null, sources: [], close: false, error: null, websocketUUID: newInvocation.uuid, }); // Close HTTP stream-able chunk response method because we will swap to agents now. writeResponseChunk(response, { id: uuid, type: "statusResponse", textResponse: "@agent: Swapping over to agent chat. Type /exit to exit agent execution loop early.", sources: [], close: true, error: null, animate: true, }); return true; } return false; } module.exports = { grepAgents, getAndClearInvocationAttachments };