// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Microsoft.Teams.AI.Messages; using Microsoft.Teams.AI.Models; namespace Microsoft.Teams.AI.Prompts; public partial class ChatPrompt { public async Task Send(IMessage message, CancellationToken cancellationToken = default) { return await Send(message, null, null, cancellationToken).ConfigureAwait(false); } public async Task> Send(string text, CancellationToken cancellationToken = default) { return await Send(text, null, null, cancellationToken).ConfigureAwait(false); } public async Task> Send(string text, OnStreamChunk? onChunk, CancellationToken cancellationToken = default) { return await Send(text, null, onChunk, cancellationToken).ConfigureAwait(false); } public Task> Send(string text, IChatPrompt.RequestOptions? options, OnStreamChunk? onChunk = null, CancellationToken cancellationToken = default) { var message = UserMessage.Text(text); return Send((IMessage)message, options, onChunk, cancellationToken); } public Task> Send(IContent[] content, IChatPrompt.RequestOptions? options = null, OnStreamChunk? onChunk = null, CancellationToken cancellationToken = default) { var message = UserMessage.Text(content); return Send((IMessage)message, options, onChunk, cancellationToken); } public Task> Send(UserMessage message, IChatPrompt.RequestOptions? options = null, OnStreamChunk? onChunk = null, CancellationToken cancellationToken = default) { return Send((IMessage)message, options, onChunk, cancellationToken); } public Task> Send(UserMessage> message, IChatPrompt.RequestOptions? options = null, OnStreamChunk? onChunk = null, CancellationToken cancellationToken = default) { return Send((IMessage)message, options, onChunk, cancellationToken); } public async Task> Send(IMessage message, IChatPrompt.RequestOptions? options = null, OnStreamChunk? onChunk = null, CancellationToken cancellationToken = default) { var messages = options?.Messages ?? Messages; var buffer = string.Empty; var prompt = Template is not null ? await Template.Render(null, cancellationToken).ConfigureAwait(false) : null; async Task OnChunk(string chunk) { if (chunk == string.Empty || onChunk is null) return; buffer += chunk; try { await onChunk(buffer).ConfigureAwait(false); buffer = string.Empty; } catch { return; } } var functions = new FunctionCollection(); foreach (var kvp in Functions) { functions[kvp.Key] = kvp.Value; } var instructions = prompt is null ? null : new DeveloperMessage(prompt); // allow plugins to modify functions and instructions before each send foreach (var plugin in Plugins) { functions = await plugin.OnBuildFunctions(this, functions, cancellationToken).ConfigureAwait(false); instructions = await plugin.OnBuildInstructions(this, instructions, cancellationToken).ConfigureAwait(false); } ChatModelOptions requestOptions = new(Invoke(functions)) { Functions = functions.List, Messages = messages, Prompt = instructions, Options = options is null ? default : options.Request, }; ModelMessage? res; try { Logger.Debug(message); foreach (var plugin in Plugins) { message = await plugin.OnBeforeSend(this, message, requestOptions.Options, cancellationToken).ConfigureAwait(false); } if (onChunk is null) { res = await Model.Send(message, requestOptions, cancellationToken).ConfigureAwait(false); } else { res = await Model.Send(message, requestOptions, new Stream(OnChunk), cancellationToken).ConfigureAwait(false); } Logger.Debug(res); foreach (var plugin in Plugins) { res = (ModelMessage)await plugin.OnAfterSend(this, res, requestOptions.Options, cancellationToken).ConfigureAwait(false); } return res; } catch (Exception ex) { ErrorEvent(Model, ex); throw new Exception("An error occurred while attempting to send the message", ex); } } }