UNPKG

@microsoft/teams-ai

Version:

SDK focused on building AI based applications for Microsoft Teams.

143 lines 6.34 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.MonologueAugmentation = void 0; const validators_1 = require("../validators"); const types_1 = require("../types"); const ActionAugmentationSection_1 = require("./ActionAugmentationSection"); /** * @private */ const MISSING_ACTION_FEEDBACK = `The JSON returned had errors. Apply these fixes:\nadd the "action" property to "instance"`; /** * @private */ const SAY_REDIRECT_FEEDBACK = `The JSON returned was missing an action. Return a valid JSON object that contains your thoughts and uses the SAY action.`; /** * The 'monologue' augmentation. * @remarks * This augmentation adds support for an inner monologue to the prompt. The monologue helps the LLM * to perform chain-of-thought reasoning across multiple turns of conversation. */ class MonologueAugmentation { _section; _monologueValidator = new validators_1.JSONResponseValidator(types_1.InnerMonologueSchema, `No valid JSON objects were found in the response. Return a valid JSON object with your thoughts and the next action to perform.`); _actionValidator; /** * Creates a new `MonologueAugmentation` instance. * @param {ChatCompletionAction[]} actions - List of actions supported by the prompt. */ constructor(actions) { actions = appendSAYAction(actions); this._section = new ActionAugmentationSection_1.ActionAugmentationSection(actions, [ `Return a JSON object with your thoughts and the next action to perform.`, `Only respond with the JSON format below and base your plan on the actions above.`, `If you're not sure what to do, you can always say something by returning a SAY action.`, `If you're told your JSON response has errors, do your best to fix them.`, `Response Format:`, `{"thoughts":{"thought":"<your current thought>","reasoning":"<self reflect on why you made this decision>","plan":"- short bulleted\\n- list that conveys\\n- long-term plan"},"action":{"name":"<action name>","parameters":{"<name>":"<value>"}}}` ].join('\n')); this._actionValidator = new validators_1.ActionResponseValidator(actions, true); } /** * @returns {PromptSection|undefined} Returns an optional prompt section for the augmentation. */ createPromptSection() { return this._section; } /** * Validates a response to a prompt. * @param {TurnContext} context - Context for the current turn of conversation with the user. * @param {Memory} memory - An interface for accessing state values. * @param {Tokenizer} tokenizer - Tokenizer to use for encoding and decoding text. * @param {PromptResponse<string>} response - Response to validate. * @param {number} remaining_attempts - Number of remaining attempts to validate the response. * @returns {Validation} A `Validation` object. */ async validateResponse(context, memory, tokenizer, response, remaining_attempts) { // Validate that we got a well-formed inner monologue const validationResult = await this._monologueValidator.validateResponse(context, memory, tokenizer, response, remaining_attempts); if (!validationResult.valid) { // Catch the case where the action is missing. // - GPT-3.5 gets stuck in a loop here sometimes so we'll redirect it to just use the SAY action. if (validationResult.feedback == MISSING_ACTION_FEEDBACK) { validationResult.feedback = SAY_REDIRECT_FEEDBACK; } return validationResult; } // Validate that the action exists and its parameters are valid const monologue = validationResult.value; const parameters = JSON.stringify(monologue.action.parameters ?? {}); const message = { role: 'assistant', content: undefined, function_call: { name: monologue.action.name, arguments: parameters } }; const actionValidation = await this._actionValidator.validateResponse(context, memory, tokenizer, { status: 'success', message }, remaining_attempts); if (!actionValidation.valid) { return actionValidation; } // Return the validated monologue return validationResult; } /** * Creates a plan given validated response value. * @param {TurnContext} context - Context for the current turn of conversation. * @param {Memory} memory - An interface for accessing state variables. * @param {PromptResponse<InnerMonologue|undefined>} response - The validated and transformed response for the prompt. * @returns {Plan} The created plan. */ createPlanFromResponse(context, memory, response) { // Identify the action to perform let command; const monologue = response.message.content; if (monologue.action.name == 'SAY') { command = { type: 'SAY', response: { ...response.message, content: monologue.action.parameters?.text || '' } }; } else { command = { type: 'DO', action: monologue.action.name, parameters: monologue.action.parameters ?? {} }; } return Promise.resolve({ type: 'plan', commands: [command] }); } } exports.MonologueAugmentation = MonologueAugmentation; /** * @private * @param {ChatCompletionAction[]} actions - List of actions * @returns {ChatCompletionAction[]} The modified list of actions. */ function appendSAYAction(actions) { const clone = actions.slice(); clone.push({ name: 'SAY', description: 'use to ask the user a question or say something', parameters: { type: 'object', properties: { text: { type: 'string', description: 'text to say or question to ask' } }, required: ['text'] } }); return clone; } //# sourceMappingURL=MonologueAugmentation.js.map