@microsoft/teams-ai
Version:
SDK focused on building AI based applications for Microsoft Teams.
127 lines • 5.73 kB
JavaScript
;
/**
* @module teams-ai
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromptSectionBase = void 0;
/**
* Abstract Base class for most prompt sections.
* @remarks
* This class provides a default implementation of `renderAsText()` so that derived classes only
* need to implement `renderAsMessages()`.
*/
class PromptSectionBase {
required;
tokens;
separator;
textPrefix;
/**
* Creates a new 'PromptSectionBase' instance.
* @param {number} tokens - Optional. Sizing strategy for this section. Defaults to -1, 'auto'.
* @param {boolean} required - Optional. Indicates if this section is required. Defaults to `true`.
* @param {string} separator - Optional. Separator to use between sections when rendering as text. Defaults to `\n`.
* @param {string} textPrefix - Optional. Prefix to use for text output. Defaults to an empty string.
*/
constructor(tokens = -1, required = true, separator = '\n', textPrefix = '') {
this.required = required;
this.tokens = tokens;
this.separator = separator;
this.textPrefix = textPrefix;
}
/**
* Renders the prompt section as a string of text.
* @param {TurnContext} context - Context for the current turn of conversation.
* @param {Memory} memory - Interface for accessing state variables.
* @param {PromptFunctions} functions - Functions for rendering prompts.
* @param {Tokenizer} tokenizer - Tokenizer to use for encoding/decoding text.
* @param {number} maxTokens - Maximum number of tokens allowed for the rendered prompt.
* @returns {Promise<RenderedPromptSection<string>>} The rendered prompt section.
*/
async renderAsText(context, memory, functions, tokenizer, maxTokens) {
// Render as messages
const asMessages = await this.renderAsMessages(context, memory, functions, tokenizer, maxTokens);
if (asMessages.output.length === 0) {
return { output: '', length: 0, tooLong: false };
}
// Convert to text
let text = asMessages.output.map((message) => PromptSectionBase.getMessageText(message)).join(this.separator);
// Calculate length
const prefixLength = tokenizer.encode(this.textPrefix).length;
const separatorLength = tokenizer.encode(this.separator).length;
let length = prefixLength + asMessages.length + (asMessages.output.length - 1) * separatorLength;
// Truncate if fixed length
text = this.textPrefix + text;
if (this.tokens > 1.0 && length > this.tokens) {
const encoded = tokenizer.encode(text);
text = tokenizer.decode(encoded.slice(0, this.tokens));
length = this.tokens;
}
return { output: text, length: length, tooLong: length > maxTokens };
}
/**
* Calculates the token budget for the prompt section.
* @remarks
* If the section has a fixed length, the budget will be the minimum of the section's length
* and the maximum number of tokens. Otherwise, the budget will be the maximum number of tokens.
* @param {number} maxTokens - Maximum number of tokens allowed for the rendered prompt.
* @returns {number} The token budget for the prompt section.
*/
getTokenBudget(maxTokens) {
return this.tokens > 1.0 ? Math.min(this.tokens, maxTokens) : maxTokens;
}
/**
* Helper method for returning a list of messages from `renderAsMessages()`.
* @remarks
* If the section has a fixed length, the function will truncate the list of messages to
* fit within the token budget.
* @param {Message[]} output - List of messages to return.
* @param {number} length Total number of tokens consumed by the list of messages.
* @param {Tokenizer} tokenizer Tokenizer to use for encoding/decoding text.
* @param {number} maxTokens Maximum number of tokens allowed for the rendered prompt.
* @returns {RenderedPromptSection<Message[]>} The rendered prompt section.
*/
returnMessages(output, length, tokenizer, maxTokens) {
// Truncate if fixed length
if (this.tokens > 1.0) {
while (length > this.tokens) {
const msg = output.pop();
const encoded = tokenizer.encode(PromptSectionBase.getMessageText(msg));
length -= encoded.length;
if (length < this.tokens) {
const delta = this.tokens - length;
const truncated = tokenizer.decode(encoded.slice(0, delta));
output.push({ role: msg.role, content: truncated });
length += delta;
}
}
}
return { output: output, length: length, tooLong: length > maxTokens };
}
/**
* Returns the content of a message as a string.
* @param {Message} message - Message to get the text of.
* @returns {string} The message content as a string.
*/
static getMessageText(message) {
let text = message.content ?? '';
if (Array.isArray(text)) {
text = text
.filter((part) => part.type === 'text')
.map((part) => part.text)
.join(' ');
}
else if (message.function_call) {
text = JSON.stringify(message.function_call);
}
else if (message.name) {
text = `${message.name} returned ${text}`;
}
return text;
}
}
exports.PromptSectionBase = PromptSectionBase;
//# sourceMappingURL=PromptSectionBase.js.map