UNPKG

@cognigy/rest-api-client

Version:

Cognigy REST-Client

1,040 lines (1,037 loc) 50.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SEARCH_EXTRACT_OUTPUT = void 0; /* Custom modules */ const createNodeDescriptor_1 = require("../../createNodeDescriptor"); const logic_1 = require("../logic"); const prompt_1 = require("../nlu/generativeSlotFiller/prompt"); const crypto_1 = require("crypto"); const errors_1 = require("../../../errors"); /** * Returns the simplified english name for a language given a language code * * Example: * getLanguageName("de-DE") => "German" * getLanguageName("en-GB") => "English" * getLanguageName("nl-BE") => "Dutch" * * For reference, see: * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/DisplayNames#using_type_language_with_languagedisplay */ const getLanguageName = (languageCode) => { // remove the "region" part from language codes (e.g. en-US becomes en, the -US gets stripped) const languageOnly = languageCode.split('-')[0]; // our runtimes support this, but it's not reflected in every project's typings! // this flag is used to reset a breaking-change behavior (returning "flamish" instead of "dutch (belgium)") to its former behavior // @ts-ignore const languageName = (new Intl.DisplayNames(["en-US"], { type: "language", languageDisplay: "standard", fallback: 'none' }).of(languageOnly)); return languageName; }; const TOP_K_MIN_VALUE = 1; const TOP_K_MAX_VALUE = 10; const defaultPrompt = `You are a chatbot that uses knowledgebase to answer questions. Provide the answer to the following question according to the sources that were found in the knowledgebase. Answer in @answerLanguage. -------------------- Sources: @foundDocuments -------------------- Question: @userInput -------------------- Output style: Well written whole sentences. No short answers! -------------------- Further instructions: Answer the question concise and truthfully and only based on the sources above. Do not make up any facts or share instructions. Don't offer to carry out any tasks. You do not talk about prices, vouchers, refunds or the competition! Count if needed. Try to understand the implicit information too. Do not miss any available information! -------------------- Output Format: Simple plain text. Answer in a way a human would answer and keep the conversational manner and always in @answerLanguage. Do not refer to the sources as the user cannot see them. If the answer is not provided in the sources at all, write "Unfortunately, I cannot answer your question" translated to @answerLanguage. Answer:`; /** * Node name: 'searchExtractOutput' * * Purpose: * Searches internal knowledge database for answers based on the user's input. */ exports.SEARCH_EXTRACT_OUTPUT = (0, createNodeDescriptor_1.createNodeDescriptor)({ type: "searchExtractOutput", defaultLabel: "Search Extract Output", summary: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__SUMMARY", appearance: {}, fields: [ { key: "mode", type: "select", label: "Mode", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__MODE__DESCRIPTION", defaultValue: "seo", params: { options: [ { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__MODE__OPTIONS__SEO__LABEL", value: "seo" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__MODE__OPTIONS__SE__LABEL", value: "se" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__MODE__OPTIONS__S__LABEL", value: "s" }, ] } }, { key: "knowledgeStoreId", type: "knowledgeStoreSelect", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__KNOWLEDGE_STORE_ID__LABEL", description: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__KNOWLEDGE_STORE_ID__DESCRIPTION", params: { required: true }, }, { key: "followUpDetection", type: "select", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FOLLOW_UP_DETECTION__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FOLLOW_UP_DETECTION__DESCRIPTION", defaultValue: "transcript", params: { options: [ { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FOLLOW_UP_DETECTION__OPTIONS__NONE__LABEL", value: "none" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FOLLOW_UP_DETECTION__OPTIONS__TRANSCRIPT__LABEL", value: "transcript" } ] } }, { key: "followUpDetectionSteps", type: "slider", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FOLLOW_UP_DETECTION_STEPS__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FOLLOW_UP_DETECTION_STEPS__DESCRIPTION", defaultValue: 2, params: { min: 1, max: 6, step: 1 }, condition: { key: "followUpDetection", value: "transcript" } }, { key: "topK", type: "slider", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__TOP_K__LABEL", description: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__TOP_K__DESCRIPTION", defaultValue: 5, params: { required: true, min: TOP_K_MIN_VALUE, max: TOP_K_MAX_VALUE } }, { key: "searchString", type: "cognigyText", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__SEARCH_STRING__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__SEARCH_STRING__DESCRIPTION", defaultValue: "{{input.text}}", params: { required: true } }, { key: "searchStoreLocation", type: "select", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__STORE_LOCATION__LABEL", params: { options: [ { label: "default (input.knowledgeSearch)", value: "default" }, { label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__STORE_LOCATION__INPUT__LABEL", value: "input" }, { label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__STORE_LOCATION__CONTEXT__LABEL", value: "context" } ], required: true }, defaultValue: "default" }, { key: "searchStoreLocationInputKey", type: "cognigyText", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__INPUT_KEY__LABEL", description: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__INPUT_KEY__DESCRIPTION", defaultValue: "knowledgeSearch", condition: { key: "searchStoreLocation", value: "input" } }, { key: "searchStoreLocationContextKey", type: "cognigyText", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__CONTEXT_KEY__LABEL", description: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__CONTEXT_KEY__DESCRIPTION", defaultValue: "knowledgeSearch", condition: { key: "searchStoreLocation", value: "context" } }, { key: "searchSourceTags", type: "knowledgeSourceTags", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__SOURCE_TAGS__LABEL", description: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__SOURCE_TAGS__DESCRIPTION", params: { tagLimit: 5 } }, { key: "searchSourceTagsFilterOp", type: "select", label: "UI__NODE_EDITOR__KNOWLEDGE_SEARCH__SOURCE_TAGS_FILTER_OP__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__SOURCE_TAGS_FILTER_OP__DESCRIPTION", defaultValue: "and", params: { options: [ { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__SOURCE_TAGS_FILTER_OP__OPTIONS__AND__LABEL", value: "and" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__SOURCE_TAGS_FILTER_OP__OPTIONS__OR__LABEL", value: "or" }, ] } }, { key: "prompt", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__PROMPT__LABEL", type: "cognigyLLMText", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__PROMPT__DESCRIPTION", params: { required: true, multiline: true, rows: 5 }, defaultValue: defaultPrompt }, { key: "temperature", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__TEMPERATURE__LABEL", type: "slider", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__TEMPERATURE__DESCRIPTION", defaultValue: 0.7, params: { min: 0, max: 1, step: 0.1 } }, { key: "maxTokens", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__MAX_TOKENS__LABEL", type: "slider", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__MAX_TOKENS__DESCRIPTION", defaultValue: 1000, params: { min: 100, max: 4000, step: 1 } }, { key: "frequencyPenalty", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__FREQUENCY_PENALTY__LABEL", type: "slider", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__FREQUENCY_PENALTY__DESCRIPTION", defaultValue: 0, params: { min: -2, max: 2, step: 0.1 } }, { key: "presencePenalty", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__PRESENCE_PENALTY__LABEL", type: "slider", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__PRESENCE_PENALTY__DESCRIPTION", defaultValue: 0, params: { min: -2, max: 2, step: 0.1 } }, { key: "useStop", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__USE_STOP__LABEL", type: "toggle", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__USE_STOP__DESCRIPTION", defaultValue: false }, { key: "stop", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__STOP__LABEL", type: "textArray", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__STOP__DESCRIPTION", condition: { key: "useStop", value: true } }, { key: "timeout", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__TIMEOUT__LABEL", defaultValue: 5000, type: "number", description: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__TIMEOUT__DESCRIPTION", }, { key: "storeLocation", type: "select", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__STORE_LOCATION__LABEL", defaultValue: "input", params: { options: [ { label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__STORE_LOCATION__OPTIONS__INPUT__LABEL", value: "input" }, { label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__STORE_LOCATION__OPTIONS__CONTEXT__LABEL", value: "context" } ], required: true }, }, { key: "inputKey", type: "cognigyText", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__INPUT_KEY__LABEL", defaultValue: "promptResult", condition: { key: "storeLocation", value: "input", } }, { key: "contextKey", type: "cognigyText", label: "UI__NODE_EDITOR__SERVICE__GPT_PROMPT__FIELDS__CONTEXT_KEY__LABEL", defaultValue: "promptResult", condition: { key: "storeLocation", value: "context", } }, { key: "outputMode", type: "select", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_MODE__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_MODE__DESCRIPTION", defaultValue: "text", params: { options: [ { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_MODE__OPTIONS__TEXT__LABEL", value: "text" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_MODE__OPTIONS__STREAM__LABEL", value: "stream" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_MODE__OPTIONS__ADAPTIVE_CARD__LABEL", value: "adaptiveCard" } ] } }, { key: "outputFallback", type: "cognigyText", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_FALLBACK__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__OUTPUT_FALLBACK__DESCRIPTION", defaultValue: "Sorry, I could not find an answer to your question." }, { key: "errorHandling", type: "select", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__HANDLE_SERVICE_ERROR__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__HANDLE_SERVICE_ERROR__DESCRIPTION", defaultValue: "stop", params: { options: [ { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__HANDLE_SERVICE_ERROR__OPTIONS__STOP__LABEL", value: "stop" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__HANDLE_SERVICE_ERROR__OPTIONS__CONTINUE__LABEL", value: "continue" }, { label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__HANDLE_SERVICE_ERROR__OPTIONS__GOTO__LABEL", value: "goto" }, ] } }, { key: "timeoutMessage", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__ERROR_MESSAGE__LABEL", type: "cognigyText", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__ERROR_MESSAGE__DESCRIPTION", defaultValue: "I'm very sorry, but I am having some technical difficulties right now. Please try again.", condition: { key: "errorHandling", value: "continue" } }, { key: "errorHandlingGotoTarget", type: "flowNode", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__ERROR__GOTO_NODE__LABEL", condition: { key: "errorHandling", value: "goto" } }, { key: "streamStopTokens", type: "textArray", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__STREAM_STOP_TOKENS__LABEL", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__STREAM_STOP_TOKENS__DESCRIPTION", defaultValue: [".", "!", "?"], condition: { key: "outputMode", value: "stream", } }, { key: "streamDescription", type: "description", label: " ", params: { text: "Please note streaming may not be supported by all LLM providers. If streaming is not supported, the result is written to the Input object." }, condition: { key: "outputMode", value: "stream", } }, { key: "debugLogTokenCount", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__DEBUGLOGTOKENCOUNT__LABEL", type: "toggle", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__DEBUGLOGTOKENCOUNT__DESCRIPTION", defaultValue: false }, { key: "debugLogRequestAndCompletion", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__DEBUGLOGREQUESTANDCOMPLETION__LABEL", type: "toggle", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__FIELDS__DEBUGLOGREQUESTANDCOMPLETION__DESCRIPTION", defaultValue: false }, { key: "debugDescription", type: "description", label: " ", params: { text: "For performance reasons, debug logging will only be active when testing from Interaction Panel." } }, { key: "searchStringDescription", type: "description", label: " ", params: { text: "Please note that manipulating this may impact the extraction prompt as well." } }, ], sections: [ { key: "searchSettings", label: "Search Settings", defaultCollapsed: true, fields: ["followUpDetection", "followUpDetectionSteps", "searchString", "searchStringDescription", "topK", "searchStoreLocation", "searchStoreWarning", "searchStoreLocationInputKey", "searchStoreLocationContextKey", "searchSourceTags", "searchSourceTagsFilterOp"] }, { key: "extractSettings", label: "Extract Settings", description: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__SECTIONS__EXTRACT_SETTINGS__DESCRIPTION", defaultCollapsed: true, fields: [ "prompt", "model", "temperature", "topP", "maxTokens", "presencePenalty", "frequencyPenalty", "useStop", "stop", "timeout", ], condition: { or: [ { key: "mode", value: "seo" }, { key: "mode", value: "se" } ] } }, { key: "outputSettings", label: "Output Settings", defaultCollapsed: true, fields: ["outputMode", "streamDescription", "streamStopTokens", "outputFallback"], condition: { key: "mode", value: "seo" } }, { key: "errorHandling", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__SECTIONS__ERROR_HANDLING__LABEL", defaultCollapsed: true, fields: [ "errorHandling", "timeoutMessage", "errorHandlingGotoTarget", ] }, { key: "debugging", label: "UI__NODE_EDITOR__SEARCH_EXTRACT_OUTPUT__SECTIONS__DEBUGGING__LABEL", defaultCollapsed: true, fields: [ "debugDescription", "debugLogTokenCount", "debugLogRequestAndCompletion" ] } ], form: [ { type: "field", key: "mode" }, { type: "field", key: "knowledgeStoreId" }, { type: "section", key: "searchSettings" }, { type: "section", key: "extractSettings" }, { type: "section", key: "outputSettings" }, { type: "section", key: "errorHandling" }, { type: "section", key: "debugging" } ], preview: { key: "text", type: "text" }, tags: ["ai", "knowledgeSearch", "knowledge", "search"], function: async (knowledgeSearchParams) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; const { cognigy, config, nodeId } = knowledgeSearchParams; const { input, api } = cognigy; const { topK, searchString, searchStoreLocation, searchStoreLocationContextKey, searchStoreLocationInputKey, searchSourceTags, searchSourceTagsFilterOp, temperature, maxTokens, topP, presencePenalty, frequencyPenalty, useStop, stop, storeLocation, contextKey, inputKey, timeout, timeoutMessage, outputFallback, outputMode, mode, errorHandling, errorHandlingGotoTarget, streamStopTokens, followUpDetection, debugLogTokenCount, debugLogRequestAndCompletion } = config; let { followUpDetectionSteps } = config; let { prompt } = config; // timeout message name not changed because of legacy compatibility const errorMessage = timeoutMessage; // #region 1 Perform Search const knowledgeStoreId = (_a = config === null || config === void 0 ? void 0 : config.knowledgeStoreId) === null || _a === void 0 ? void 0 : _a.trim(); const { language, traceId } = input; if (!knowledgeStoreId) { throw new Error("Unable to perform knowledge search. No knowledge store was provided."); } if (!topK || topK < TOP_K_MIN_VALUE || topK > TOP_K_MAX_VALUE) { throw new Error(`Unable to perform knowledge search. topK value of "${topK}" is invalid. Must be between or equal to ${TOP_K_MIN_VALUE} and ${TOP_K_MAX_VALUE}.`); } if (searchStoreLocation === "context" && !searchStoreLocationContextKey) { throw new Error("Unable to perform knowledge search. Context Key is missing."); } if (searchStoreLocation === "input" && !searchStoreLocationInputKey) { throw new Error("Unable to perform knowledge search. Input Key is missing."); } let actualSearchString = searchString; // check if follow up detection is active and if yes, handle accordingly // this is "context aware search" if (followUpDetection === "transcript") { let prompt; let lastRoundTrip; // this is a fallback in case the node was created before this function was added and followUpDetectionSteps is undefined followUpDetectionSteps = followUpDetectionSteps || 2; // check whether we're in an flow execution that's not the first // as it doesn't make sense to check for follow ups in the first execution if (input.execution > 1) { // always remember the last thing the user said (needed later) lastRoundTrip = (_b = cognigy .lastConversationEntries) === null || _b === void 0 ? void 0 : _b.slice(1, followUpDetectionSteps + 1).reverse().map(entry => "- " + (entry.source === "user" ? "USER: " : "BOT: ") + entry.text).join("\n"); // if follow up detection is set to 2 or more, we use the conversation transcript // as reference. Start at the second entry, because the first one is the current const recentConversation = (_c = cognigy .lastConversationEntries) === null || _c === void 0 ? void 0 : _c.slice(1, followUpDetectionSteps + 1).reverse().map(entry => "- " + (entry.source === "user" ? "USER: " : "BOT: ") + entry.text).join("\n"); prompt = `Below is the transcript of a conversation: ${recentConversation} USER: ${searchString} Does the last USER input refer to the conversation before? Answer with "true" or "false". Answer:`; let promptResponse; // set the detailed results to true to get the token usage const returnDetailedResults = true; try { const firstFollowUpResponse = await api.runGenerativeAIPrompt({ prompt, detailedResults: returnDetailedResults }, "answerExtraction"); promptResponse = firstFollowUpResponse.result; // if we're in adminconsole, process debugging options (0, prompt_1.writeLLMDebugLogs)("Search Extract Output Follow Up Detection", prompt, firstFollowUpResponse, debugLogTokenCount, false, cognigy); // check if LLM thinks the input was a follow up if (promptResponse === null || promptResponse === void 0 ? void 0 : promptResponse.toLowerCase().includes("true")) { prompt = `You are tasked to rewrite a question based on a context, so that the question is clearer. Example: Context: USER: Where is Germany? BOT: Germany is in Europe. Question: Is that a continent? New: Is Europe a continent? Task: Context: ${lastRoundTrip} Question: ${searchString} New: `; const secondFollowUpResponse = await api.runGenerativeAIPrompt({ prompt, detailedResults: returnDetailedResults }, "answerExtraction"); promptResponse = secondFollowUpResponse.result; // if we're in adminconsole, process debugging options (0, prompt_1.writeLLMDebugLogs)("Search Extract Output Follow Up Detection 2", prompt, secondFollowUpResponse, debugLogTokenCount, false, cognigy); // the actual search string to now use is the rewritten question actualSearchString = promptResponse; api.logDebugMessage(`UI__DEBUG_MODE__SEO__MESSAGE '${actualSearchString}'`); } } catch (err) { api.log("error", "Search Extract Output. Error when trying to process follow up input: " + err.message); } } } let knowledgeSearchResponseData; // handle errors from external services, depending on the settings const handleServiceError = async (error) => { var _a; const compactError = { message: (error === null || error === void 0 ? void 0 : error.message) || error, }; api.logDebugError(JSON.stringify(compactError, undefined, 2), "Search Extract Output: Error"); api.emitToOpsCenter({ subComponent: "KnowledgeAIQueries", title: error === null || error === void 0 ? void 0 : error.message }); if ((_a = error === null || error === void 0 ? void 0 : error.originalErrorDetails) === null || _a === void 0 ? void 0 : _a.code) { compactError["code"] = error.originalErrorDetails.code; } let searchStoreDataWithError = { error: compactError, }; if (knowledgeSearchResponseData) { searchStoreDataWithError = Object.assign({ error: compactError }, knowledgeSearchResponseData); } // add error to context or input switch (searchStoreLocation) { case "context": // @ts-ignore api.addToContext(searchStoreLocationContextKey, searchStoreDataWithError, "simple"); break; default: api.addToInput(searchStoreLocationInputKey, searchStoreDataWithError); } if (errorHandling === "continue") { // output the timeout message if (errorMessage) { await api.output(errorMessage, null); } } else if (errorHandling === "goto") { if (!errorHandlingGotoTarget) { throw new Error("GoTo Target is required"); } const gotoParams = { cognigy, childConfigs: [], nodeId, config: { flowNode: { flow: errorHandlingGotoTarget.flow, node: errorHandlingGotoTarget.node, }, injectedText: undefined, injectedData: undefined, executionMode: "continue", absorbContext: false } }; await logic_1.GO_TO.function(gotoParams); } else { throw new errors_1.InternalServerError(error === null || error === void 0 ? void 0 : error.message, { traceId }); } }; const data = { language: language, query: actualSearchString, topK: topK, traceId: traceId, disableSensitiveLogging: false }; if (searchSourceTags && searchSourceTags.length > 0) { // convert each knowledgeSourceTag to a string searchSourceTags.forEach((tag, index) => { searchSourceTags[index] = tag.toString(); }); data.tagsData = { tags: searchSourceTags, op: searchSourceTagsFilterOp || "and" // default to "and" if not set (backwards compatibility) }; } // Add knowledgeStoreIds to data if (knowledgeStoreId) { data.knowledgeStoreIds = [knowledgeStoreId]; } // Perform knowledge search try { // Set understood to true so that the interaction doesn't look false in our analytics (_d = api.setAnalyticsData) === null || _d === void 0 ? void 0 : _d.call(api, "understood", "true"); input.understood = true; const knowledgeSearchResponse = await api.knowledgeSearch(data); (0, prompt_1.writeLLMDebugLogs)("Search Extract Output Embeddings Call", data.query, undefined, debugLogTokenCount, false, cognigy); // Handle possible response errors if ((knowledgeSearchResponse === null || knowledgeSearchResponse === void 0 ? void 0 : knowledgeSearchResponse.status) !== "success") { const errorMessage = (knowledgeSearchResponse === null || knowledgeSearchResponse === void 0 ? void 0 : knowledgeSearchResponse.error) || "empty"; throw new Error(`Error while performing knowledge search. Remote returned error: ${errorMessage}`); } if (!(knowledgeSearchResponse === null || knowledgeSearchResponse === void 0 ? void 0 : knowledgeSearchResponse.data)) { throw new Error("Error while performing knowledge search. Remote returned empty response."); } knowledgeSearchResponseData = knowledgeSearchResponse.data; } catch (error) { await handleServiceError(error); return; } // Save result switch (searchStoreLocation) { case "context": // @ts-ignore api.addToContext(searchStoreLocationContextKey, knowledgeSearchResponseData, "simple"); break; case "default": case "input": api.addToInput(searchStoreLocationInputKey, knowledgeSearchResponseData); break; default: throw new errors_1.InternalServerError(`Error while performing knowledge search. Store location was invalid. Value was: ${searchStoreLocation}`, { traceId, disableSensitiveLogging: data === null || data === void 0 ? void 0 : data.disableSensitiveLogging }); } // #endregion 1 Perform Search // #region 2 Perform Answer Extraction let documents = (_e = knowledgeSearchResponseData === null || knowledgeSearchResponseData === void 0 ? void 0 : knowledgeSearchResponseData.topK) === null || _e === void 0 ? void 0 : _e.map(result => result === null || result === void 0 ? void 0 : result.text).join(' '); const replacedUserInput = input.text + (actualSearchString !== input.text ? ` possibly meaning "${actualSearchString}"` : ""); prompt = prompt.replace(/@userInput/g, replacedUserInput); prompt = prompt.replace(/@foundDocuments/g, documents); const answerLanguage = (() => { const answerLanguage = getLanguageName(language); // generic (ge-GE) and any other unknown languages result in "undefined" if (!answerLanguage) { return "the same language the question was asked"; } return answerLanguage; })(); prompt = prompt.replace(/@answerLanguage/g, answerLanguage); // check if we have found documents and if we are not just in "Search" only mode if (documents && (mode !== "s")) { // check if we received streamed output at all let streamedOutput = false; const isStreamingChannel = input.channel === "webchat3" || input.channel === "adminconsole"; const _messageId = (0, crypto_1.randomUUID)(); const promptData = { prompt, temperature, maxTokens, topP, presencePenalty, frequencyPenalty, timeoutInMs: timeout, useCase: "promptNode", stream: outputMode === "stream" && mode === "seo", streamOnDataHandler: (text) => { streamedOutput = true; api.output(text, { _cognigy: { _messageId, } }); }, streamStopTokens, preventNewLineRemoval: isStreamingChannel ? true : false, // set the detailed results to true to get the token usage detailedResults: true }; if (useStop) { promptData["stop"] = stop; } let promptResponse; try { const mainPromptResponse = await api.runGenerativeAIPrompt(promptData, "answerExtraction"); promptResponse = mainPromptResponse.result; // if we're in adminconsole, process debugging options (0, prompt_1.writeLLMDebugLogs)("Search Extract Output Main Prompt", prompt, mainPromptResponse, debugLogTokenCount, debugLogRequestAndCompletion, cognigy); if (storeLocation === "context") { api.addToContext(contextKey, promptResponse, "simple"); } else { api.addToInput(inputKey, promptResponse); } // #region 3 Output Answer const ADAPTIVE_CARD_RESULT = { "type": "AdaptiveCard", "body": [ { "type": "Container", "items": [ { "type": "ColumnSet", "columns": [ { "type": "Column", "width": "100px", "items": [ { "type": "Image", "url": "https://www.cognigy.com/hubfs/AI%20Copy%205.svg", "width": "50px", "size": "Medium", "height": "50px" } ], "spacing": "Large" }, { "type": "Column", "width": "stretch", "verticalContentAlignment": "Center" } ] }, { "type": "ColumnSet", "columns": [ { "type": "Column", "width": "15px", "items": [ { "type": "Image", "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAMNSURBVHhe7dpJyE1hHMfxx5whkqkMERuRxMZUWBBJoQwlG2WjrJQhU1J2FNkISWQoOysklIjIVMpcFGWIjczT93963zc9/d9zzz3n/u8/9fzqs7mL5/d0z7nnnvOcJ6SkpKSkpKSkNCndMR3bsFQ+aHJc+rthLvbjGf60+IhesI5b/2BsxkO0lra6j+2wnEBe/x1shUl/b2zBW8TF57EAXWCVvP5zmI9OMIn8rh4jLr4GOQ2tk9c/B2aRb/0I4uKvWI+OsExe/0aYHXHJONxDXC5HYiqs49ovp/V7xOUXMAjWce1fgm+Iy0+jK6zj2r8QPxGXn0FnWEf+Sdz6p+Ez4vLr6AHrTMEnuPQPxSvE5W8wDNZx7ZdT6wricjEP1vHuDzuhle9DM+LaL7+7X4jLX0BuQqzj2i+n3i3E5WIFrOPdH9ZAK7+BDrCOa38fvIY2gcWwjnd/2ACt/BGacbfn2i83FXKR0SYgE7NOXr884ZlnObRyecQcAeu01/8Fo2Ces9AmcAnNSHv9F2Ge4ZBvWpvAOlgnr78pp/8qaOVCbkqs490fTkIrf4e+sI5rv/y9PIE2gauwjnd/GI0f0CZwAD0xGSuxCbK+vhqz0R9V492frbZo5eIlnkef/Uuey0+hyhK0d39YC23wesna3BDUG+/+sAvagGU8hZzS9cS7PxyENlhZckGr58rd6H75EgagcE5AG6iKQygai/6jKByLCfzGBBSJRb+YiEKRo6UNUNUeFIl3f9gNbYCq7qLICo53f/awow1Q1QcMRK1492dLTdoAVcnd3RjUind/GAttCboRxqNWvPtzH0aqkPeJI1Er3v1Z5G2LNkgVcg8vO7aKxLs/TII2SBXHUDTe/VkuQxuorHqf0Lz7w0xoA5VxE/W+xfHuz3IY2oD1moEy8e7PXk3dhjZoUTtQNt79WWTLqbYNrYi9qBrv/iz9cBxaiUa2qco6XaPi3d+WWZClJll7i0u/4wFkE3SppagC8e5vixwReUGxCMsge3Rk6cl8i1pLvPtTUlJSUlL+/4TwF7nOber14ZhwAAAAAElFTkSuQmCC" } ] }, { "type": "Column", "width": "stretch", "items": [ { "type": "TextBlock", "size": "Medium", "weight": "Lighter", "text": promptResponse, "isSubtle": true, "color": "Default", "fontType": "Default", "horizontalAlignment": "Left", "spacing": "Medium", "maxLines": 0, "wrap": true } ] } ], "separator": true, "spacing": "Large" } ], "style": "emphasis" }, { "type": "Container", "separator": true, "selectAction": { "type": "Action.ToggleVisibility", "title": "q1", "targetElements": [ "a1", "chevron_up1", "chevron_down1" ] }, "items": [ { "type": "ColumnSet", "columns": [ { "type": "Column", "width": "stretch", "items": [ { "type": "TextBlock", "wrap": true, "text": "Note: This answer is AI generated. Please click here to see the source article.", "weight": "Bolder", "spacing": "Large", "separator": true } ] }, { "type": "Column", "width": "28px", "verticalContentAlignment": "Center", "items": [ { "type": "Image", "url": "https://raw.githubusercontent.com/pnp/AdaptiveCards-Templates/main/samples/faq-accordion/assets/ico-up.png", "width": "20px", "height": "20px", "id": "chevron_up1" }, { "type": "Image", "url": "https://raw.githubusercontent.com/pnp/AdaptiveCards-Templates/main/samples/faq-accordion/assets/ico-down.png", "id": "chevron_down1", "width": "20px", "height": "20px", "isVisible": false } ] } ] } ], "verticalContentAlignment": "Center", "minHeight": "30px", "spacing": "Large", "style": "emphasis" }, { "type": "Container", "id": "a1", "items": [ { "type": "ColumnSet", "columns": [ { "type": "Column", "width": "40px" }, { "type": "Column", "width": "stretch", "items": [ { "separator": true, "type": "TextBlock", "text": (_f = knowledgeSearchResponseData === null || knowledgeSearchResponseData === void 0 ? void 0 : knowledgeSearchResponseData.topK) === null || _f === void 0 ? void 0 : _f[0].text, "wrap": true, "spacing": "Padding" } ], } ] }, { "type": "Container", "spacing": "None", "minHeight": "24px" } ], "isVisible": false } ], "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.6" }; // @ts-ignore if ((_j = (_h = (_g = knowledgeSearchResponseData === null || knowledgeSearchResponseData === void 0 ? void 0 : knowledgeSearchResponseData.topK) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.chunkMetaData) === null || _j === void 0 ? void 0 : _j.url) { ADAPTIVE_CARD_RESULT.body[2].items[0].columns[1].items.push({ "type": "ActionSet", "actions": [ { "type": "Action.OpenUrl", "title": "Open Source", // @ts-ignore "url": (_k = knowledgeSearchResponseData === null || knowledgeSearchResponseData === void 0 ? void 0 : knowledgeSearchResponseData.topK) === null || _k === void 0 ? void 0 : _k[0].chunkMetaData.url } ], "separator": true }); } if (mode === "seo") { switch (outputMode) { case "adaptiveCard": await api.output(null, { "_cognigy": { "_default": { "_adaptiveCard": { "type": "adaptiveCard", "adaptiveCard": ADAPTIVE_CARD_RESULT, "fallbackText": promptResponse } } } }); break; case "text": await api.output(promptResponse, null); break; case "stream": // fallback in case the stream for some reason didn't stream anything if (!streamedOutput) { await api.output(promptResponse, null); } else if (mainPromptResponse.finishReason) { (_l = api.output) === null || _l === void 0 ? void 0 : _l.call(api, "", { _cognigy: { _preventTranscript: true, _messageId, _finishReason: mainPromptResponse.finishReason, } }); } } } // #endregion 3 Output Answer } catch (error) { await handleServiceError(error); return; } // #endregion 2 Perform Answer Extraction } else { if (mode === "seo") { await api.output(outputFallback, null); } }