Skip to content
22 changes: 11 additions & 11 deletions Libraries/Microsoft.Teams.AI.Models.OpenAI/OpenAIChatModel.Send.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Text;
Expand All @@ -19,14 +19,14 @@ public async Task<IMessage> Send(IMessage message, ChatCompletionOptions? option
{
Functions = [],
Messages = []
}, cancellationToken);
}, cancellationToken).ConfigureAwait(false);

return res;
}

public async Task<ModelMessage<string>> Send(IMessage message, ChatModelOptions<ChatCompletionOptions> options, CancellationToken cancellationToken = default)
{
var messages = await CallFunctions(message, options, cancellationToken);
var messages = await CallFunctions(message, options, cancellationToken).ConfigureAwait(false);
var chatMessages = messages.Select(m => m.ToOpenAI()).ToList();

if (options.Prompt is not null)
Expand All @@ -48,14 +48,14 @@ public async Task<ModelMessage<string>> Send(IMessage message, ChatModelOptions<
var result = await ChatClient.CompleteChatAsync(
chatMessages,
requestOptions,
CancellationToken.None
);
cancellationToken
).ConfigureAwait(false);

var modelMessage = ChatMessage.CreateAssistantMessage(result.Value).ToTeams();

if (modelMessage.HasFunctionCalls)
{
return await Send(modelMessage, options, cancellationToken);
return await Send(modelMessage, options, cancellationToken).ConfigureAwait(false);
}

messages.Add(modelMessage);
Expand All @@ -70,7 +70,7 @@ public async Task<ModelMessage<string>> Send(IMessage message, ChatModelOptions<

public async Task<ModelMessage<string>> Send(IMessage message, ChatModelOptions<ChatCompletionOptions> options, IStream stream, CancellationToken cancellationToken = default)
{
var messages = await CallFunctions(message, options, cancellationToken);
var messages = await CallFunctions(message, options, cancellationToken).ConfigureAwait(false);
var chatMessages = messages.Select(m => m.ToOpenAI()).ToList();

if (options.Prompt is not null)
Expand All @@ -89,7 +89,7 @@ public async Task<ModelMessage<string>> Send(IMessage message, ChatModelOptions<
requestOptions.Tools.Add(tool);
}

var res = ChatClient.CompleteChatStreamingAsync(chatMessages, requestOptions, CancellationToken.None);
var res = ChatClient.CompleteChatStreamingAsync(chatMessages, requestOptions, cancellationToken);
var content = new StringBuilder();
var toolCalls = new StreamingChatToolCallsBuilder();

Expand All @@ -108,12 +108,12 @@ public async Task<ModelMessage<string>> Send(IMessage message, ChatModelOptions<
}

content.Append(delta);
stream.Emit(delta.ToString());
await stream.EmitAsync(delta.ToString()).ConfigureAwait(false);

if (chunk.FinishReason == ChatFinishReason.ToolCalls)
{
var input = ChatMessage.CreateAssistantMessage(toolCalls.Build()).ToTeams();
return await Send(input, options, stream, cancellationToken);
return await Send(input, options, stream, cancellationToken).ConfigureAwait(false);
}
else if (chunk.FinishReason == ChatFinishReason.Length)
{
Expand Down Expand Up @@ -152,7 +152,7 @@ protected async Task<IList<IMessage>> CallFunctions(IMessage message, ChatModelO
try
{
var args = call.Parse() ?? new Dictionary<string, object?>();
var res = await options.Invoke(call, cancellationToken);
var res = await options.Invoke(call, cancellationToken).ConfigureAwait(false);

content = res is string asString ? asString : JsonSerializer.Serialize(res);
logger.Debug(content);
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Microsoft.Teams.AI/BaseChatPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public virtual Task<FunctionCollection> OnBuildFunctions<TOptions>(IChatPrompt<T
return Task.FromResult(functions);
}

public virtual Task<DeveloperMessage?> OnBuildInstructions<TOptions>(IChatPrompt<TOptions> prompt, DeveloperMessage? instructions)
public virtual Task<DeveloperMessage?> OnBuildInstructions<TOptions>(IChatPrompt<TOptions> prompt, DeveloperMessage? instructions, CancellationToken cancellationToken = default)
{
return Task.FromResult(instructions);
}
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Microsoft.Teams.AI/ChatPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,5 @@ public interface IChatPlugin
/// <param name="prompt">the prompt</param>
/// <param name="instructions">the instructions</param>
/// <returns>the transformed instructions</returns>
public Task<DeveloperMessage?> OnBuildInstructions<TOptions>(IChatPrompt<TOptions> prompt, DeveloperMessage? instructions);
public Task<DeveloperMessage?> OnBuildInstructions<TOptions>(IChatPrompt<TOptions> prompt, DeveloperMessage? instructions, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Json.Schema;
Expand All @@ -22,7 +22,7 @@ public ChatPrompt<TOptions> Chain(IChatPrompt<TOptions> prompt)
),
async (string text) =>
{
var res = await prompt.Send(text);
var res = await prompt.Send(text).ConfigureAwait(false);
return res.Content;
}
));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Teams.AI.Prompts;
Expand All @@ -13,7 +13,16 @@ public IChatPrompt<TOptions> OnError(Action<Exception> onError)

public IChatPrompt<TOptions> OnError(Func<Exception, Task> onError)
{
ErrorEvent += (_, ex) => onError(ex).GetAwaiter().GetResult();
ErrorEvent += (_, ex) =>
{
onError(ex).ContinueWith(t =>
{
if (t.IsFaulted)
{
Logger.Error(t.Exception);
}
}, TaskScheduler.Default);
Comment thread
rido-min marked this conversation as resolved.
Comment on lines +18 to +24
};
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Humanizer;
Expand Down Expand Up @@ -36,7 +36,7 @@ public ChatPrompt<TOptions> Function(string name, string? description, JsonSchem

public Func<FunctionCall, CancellationToken, Task<object?>> Invoke(FunctionCollection functions)
{
return async (call, cancellationToken) => await _Invoke(call, functions, cancellationToken);
return async (call, cancellationToken) => await _Invoke(call, functions, cancellationToken).ConfigureAwait(false);
}

private async Task<object?> _Invoke(FunctionCall call, FunctionCollection functions, CancellationToken cancellationToken = default)
Expand All @@ -48,21 +48,21 @@ public ChatPrompt<TOptions> Function(string name, string? description, JsonSchem
{
foreach (var plugin in Plugins)
{
call = await plugin.OnBeforeFunctionCall(this, func, call, cancellationToken);
call = await plugin.OnBeforeFunctionCall(this, func, call, cancellationToken).ConfigureAwait(false);
}

var startedAt = DateTime.Now;
logger.Debug(call.Arguments);

var res = await func.Invoke(call);
var res = await func.Invoke(call).ConfigureAwait(false);
var endedAt = DateTime.Now;

logger.Debug(res);
logger.Debug($"elapse time: {(endedAt - startedAt).Humanize(3)}");

foreach (var plugin in Plugins)
{
res = await plugin.OnAfterFunctionCall(this, func, call, res, cancellationToken);
res = await plugin.OnAfterFunctionCall(this, func, call, res, cancellationToken).ConfigureAwait(false);
}

return res;
Expand Down
24 changes: 12 additions & 12 deletions Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Send.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Teams.AI.Messages;
Expand All @@ -10,17 +10,17 @@ public partial class ChatPrompt<TOptions>
{
public async Task<IMessage> Send(IMessage message, CancellationToken cancellationToken = default)
{
return await Send(message, null, null, cancellationToken);
return await Send(message, null, null, cancellationToken).ConfigureAwait(false);
}

public async Task<ModelMessage<string>> Send(string text, CancellationToken cancellationToken = default)
{
return await Send(text, null, null, cancellationToken);
return await Send(text, null, null, cancellationToken).ConfigureAwait(false);
}

public async Task<ModelMessage<string>> Send(string text, OnStreamChunk? onChunk, CancellationToken cancellationToken = default)
{
return await Send(text, null, onChunk, cancellationToken);
return await Send(text, null, onChunk, cancellationToken).ConfigureAwait(false);
}

public Task<ModelMessage<string>> Send(string text, IChatPrompt<TOptions>.RequestOptions? options, OnStreamChunk? onChunk = null, CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -49,7 +49,7 @@ public async Task<ModelMessage<string>> Send(IMessage message, IChatPrompt<TOpti
{
var messages = options?.Messages ?? Messages;
var buffer = string.Empty;
var prompt = Template is not null ? await Template.Render(null, cancellationToken) : null;
var prompt = Template is not null ? await Template.Render(null, cancellationToken).ConfigureAwait(false) : null;

async Task OnChunk(string chunk)
{
Expand All @@ -58,7 +58,7 @@ async Task OnChunk(string chunk)

try
{
await onChunk(buffer);
await onChunk(buffer).ConfigureAwait(false);
buffer = string.Empty;
}
catch { return; }
Expand All @@ -74,8 +74,8 @@ async Task OnChunk(string chunk)
// allow plugins to modify functions and instructions before each send
foreach (var plugin in Plugins)
{
functions = await plugin.OnBuildFunctions(this, functions, cancellationToken);
instructions = await plugin.OnBuildInstructions(this, instructions);
functions = await plugin.OnBuildFunctions(this, functions, cancellationToken).ConfigureAwait(false);
instructions = await plugin.OnBuildInstructions(this, instructions, cancellationToken).ConfigureAwait(false);
}

ChatModelOptions<TOptions> requestOptions = new(Invoke(functions))
Expand All @@ -94,23 +94,23 @@ async Task OnChunk(string chunk)

foreach (var plugin in Plugins)
{
message = await plugin.OnBeforeSend(this, message, requestOptions.Options, cancellationToken);
message = await plugin.OnBeforeSend(this, message, requestOptions.Options, cancellationToken).ConfigureAwait(false);
}

if (onChunk is null)
{
res = await Model.Send(message, requestOptions, cancellationToken);
res = await Model.Send(message, requestOptions, cancellationToken).ConfigureAwait(false);
}
else
{
res = await Model.Send(message, requestOptions, new Stream(OnChunk), cancellationToken);
res = await Model.Send(message, requestOptions, new Stream(OnChunk), cancellationToken).ConfigureAwait(false);
}

Logger.Debug(res);

foreach (var plugin in Plugins)
{
res = (ModelMessage<string>)await plugin.OnAfterSend(this, res, requestOptions.Options, cancellationToken);
res = (ModelMessage<string>)await plugin.OnAfterSend(this, res, requestOptions.Options, cancellationToken).ConfigureAwait(false);
}

return res;
Expand Down
20 changes: 18 additions & 2 deletions Libraries/Microsoft.Teams.AI/Stream.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Teams.AI;
Expand All @@ -19,15 +19,31 @@ public interface IStream
/// </summary>
/// <param name="text">the text chunk</param>
public void Emit(string text);

/// <summary>
/// emit a text chunk asynchronously
/// </summary>
/// <param name="text">the text chunk</param>
public Task EmitAsync(string text)
{
Emit(text);
return Task.CompletedTask;
}
}

/// <summary>
/// Streams text chunks
/// </summary>
public class Stream(OnStreamChunk onChunk) : IStream
{
[Obsolete("Use EmitAsync instead to avoid sync-over-async blocking.")]
public void Emit(string text)
{
onChunk(text).GetAwaiter().GetResult();
}
}

public Task EmitAsync(string text)
{
return onChunk(text);
Comment thread
rido-min marked this conversation as resolved.
}
}
4 changes: 2 additions & 2 deletions Libraries/Microsoft.Teams.Api/Auth/ClientCredentials.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Teams.Common.Http;
Expand Down Expand Up @@ -41,7 +41,7 @@ public async Task<ITokenResponse> Resolve(IHttpClient client, string[] scopes, C
{ "scope", string.Join(",", scopes) }
};

var res = await client.SendAsync<TokenResponse>(request, cancellationToken);
var res = await client.SendAsync<TokenResponse>(request, cancellationToken).ConfigureAwait(false);
return res.Body;
}
}
4 changes: 2 additions & 2 deletions Libraries/Microsoft.Teams.Api/Auth/TokenCredentials.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Teams.Common.Http;
Expand Down Expand Up @@ -28,6 +28,6 @@ public TokenCredentials(string clientId, string tenantId, TokenFactory token)

public async Task<ITokenResponse> Resolve(IHttpClient _client, string[] scopes, CancellationToken cancellationToken = default)
{
return await Token(TenantId, scopes);
return await Token(TenantId, scopes).ConfigureAwait(false);
}
}
Loading
Loading