UNPKG

@microsoft/teams-ai

Version:

SDK focused on building AI based applications for Microsoft Teams.

126 lines 6 kB
"use strict"; /** * @module teams-ai */ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ConversationHistory = void 0; const PromptSectionBase_1 = require("./PromptSectionBase"); const Utilities_1 = require("../Utilities"); /** * A section that renders the conversation history. */ class ConversationHistory extends PromptSectionBase_1.PromptSectionBase { variable; userPrefix; assistantPrefix; /** * Creates a new 'ConversationHistory' instance. * @param {string} variable - Name of memory variable used to store the histories `Message[]`. * @param {number} tokens - Optional. Sizing strategy for this section. Defaults to `proportional` with a value of `1.0`. * @param {boolean} required - Optional. Indicates if this section is required. Defaults to `false`. * @param {string} userPrefix - Optional. Prefix to use for user messages when rendering as text. Defaults to `user: `. * @param {string} assistantPrefix - Optional. Prefix to use for assistant messages when rendering as text. Defaults to `assistant: `. * @param {string} separator - Optional. Separator to use between messages when rendering as text. Defaults to `\n`. */ constructor(variable, tokens = 1.0, required = false, userPrefix = 'user: ', assistantPrefix = 'assistant: ', separator = '\n') { super(tokens, required, separator); this.variable = variable; this.userPrefix = userPrefix; this.assistantPrefix = assistantPrefix; } /** * @param {TurnContext} context - Context for the current turn of conversation. * @param {Memory} memory - Memory to use for rendering. * @param {PromptFunctions} functions - Prompt functions to use for rendering. * @param {Tokenizer} tokenizer - Tokenizer to use for encoding text. * @param {number} maxTokens - Maximum number of tokens allowed. * @returns {Promise<RenderedPromptSection<string>>} Rendered prompt section as a string. * @private */ async renderAsText(context, memory, functions, tokenizer, maxTokens) { // Get messages from memory const history = (memory.getValue(this.variable) ?? []).slice(); // Populate history and stay under the token budget let tokens = 0; const budget = this.tokens > 1.0 ? Math.min(this.tokens, maxTokens) : maxTokens; const separatorLength = tokenizer.encode(this.separator).length; const lines = []; for (let i = history.length - 1; i >= 0; i--) { const msg = history[i]; const message = { role: msg.role, content: Utilities_1.Utilities.toString(tokenizer, msg.content) }; const prefix = message.role === 'user' ? this.userPrefix : this.assistantPrefix; const line = prefix + message.content; const length = tokenizer.encode(line).length + (lines.length > 0 ? separatorLength : 0); // Add initial line if required if (lines.length === 0 && this.required) { tokens += length; lines.unshift(line); continue; } // Stop if we're over the token budget if (tokens + length > budget) { break; } // Add line tokens += length; lines.unshift(line); } return { output: lines.join(this.separator), length: tokens, tooLong: tokens > maxTokens }; } /** * @private * @param {TurnContext} context - Context for the current turn of conversation. * @param {Memory} memory - Memory to use for rendering. * @param {PromptFunctions} functions - Prompt functions to use for rendering. * @param {Tokenizer} tokenizer - Tokenizer to use for encoding text. * @param {number} maxTokens - Maximum number of tokens allowed. * @returns {Promise<RenderedPromptSection<Message[]>>} Rendered prompt section as a list of messages. */ async renderAsMessages(context, memory, functions, tokenizer, maxTokens) { // Get messages from memory const history = (memory.getValue(this.variable) ?? []).slice(); // Populate messages and stay under the token budget let tokens = 0; const budget = this.getTokenBudget(maxTokens); const messages = []; for (let i = history.length - 1; i >= 0; i--) { // Clone message const msg = history[i]; const message = Object.assign({}, msg); if (msg.content !== null) { message.content = Utilities_1.Utilities.toString(tokenizer, msg.content); } // Get text message length let length = tokenizer.encode(PromptSectionBase_1.PromptSectionBase.getMessageText(message)).length; // Add length of any image parts // TODO: This accounts for low detail images but not high detail images. if (Array.isArray(message.content)) { length += message.content.filter((part) => part.type === 'image').length * 85; } // Add initial message if required if (messages.length === 0 && this.required) { tokens += length; messages.unshift(message); continue; } // Stop if we're over the token budget if (tokens + length > budget) { break; } // Add message tokens += length; messages.unshift(message); } // Remove completed partial action outputs while (messages.length > 0 && messages[0].role === 'tool') { messages.shift(); } return { output: messages, length: tokens, tooLong: tokens > maxTokens }; } } exports.ConversationHistory = ConversationHistory; //# sourceMappingURL=ConversationHistory.js.map