Skip to content

Commit

Permalink
[C#] feat: AssistantsPlanner support for file_search tool annotat…
Browse files Browse the repository at this point in the history
…ions (#1913)

## Linked issues
closes: #minor

#1590, #1585 

## Details
* ~Bump `OpenAI` to 2.0.0-beta.8~
* Add `AssistantMessage` class that represents a message returned by the
OpenAI Assistant.

## Attestation Checklist

- [x] My code follows the style guidelines of this project

- I have checked for/fixed spelling, linting, and other errors
- I have commented my code for clarity
- I have made corresponding changes to the documentation (updating the
doc strings in the code is sufficient)
- My changes generate no new warnings
- I have added tests that validates my changes, and provides sufficient
test coverage. I have tested with:
  - Local testing
  - E2E testing in Teams
- New and existing unit tests pass locally with my changes
  • Loading branch information
singhk97 authored Aug 8, 2024
1 parent 29f1887 commit c5dd283
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.Teams.AI.AI.Models;
using Microsoft.Teams.AI.Tests.TestUtils;
using OpenAI.Assistants;

namespace Microsoft.Teams.AI.Tests.AITests
{
public class AssistantsMessageTest
{
[Fact]
public void Test_Constructor()
{
// Arrange
MessageContent content = OpenAIModelFactory.CreateMessageContent("message", "fileId");

// Act
AssistantsMessage assistantMessage = new AssistantsMessage(content);

// Assert
Assert.Equal(assistantMessage.MessageContent, content);

ChatMessage chatMessage = assistantMessage;
Assert.NotNull(chatMessage);
Assert.Equal(chatMessage.Content, "message");
Assert.Equal(chatMessage.Context!.Citations[0].Url, "fileId");
Assert.Equal(chatMessage.Context.Citations[0].Title, "");
Assert.Equal(chatMessage.Context.Citations[0].Content, "");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,36 @@ public static ThreadMessage CreateThreadMessage(string threadId, string message)
return ModelReaderWriter.Read<ThreadMessage>(BinaryData.FromString(json))!;
}

public static MessageContent CreateMessageContent(string message, string fileId)
{
var json = @$"{{
""id"": ""test"",
""thread_id"": ""test"",
""created_at"": 0,
""content"": [
{{
""type"": ""text"",
""text"": {{
""value"": ""{message}"",
""annotations"": [
{{
""type"": ""file_citation"",
""file_citation"": {{
""file_id"": ""{fileId}""
}}
}}
]
}}
}}
]
}}";

// Unable to directly read `MessageContent`.
var threadMessage = ModelReaderWriter.Read<ThreadMessage>(BinaryData.FromString(json))!;

return threadMessage.Content[0];
}

public static ThreadRun CreateThreadRun(string threadId, string runStatus, string? runId = null, IList<RequiredAction> requiredActions = null!)
{
var raJson = "{}";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using OpenAI.Assistants;

namespace Microsoft.Teams.AI.AI.Models
{
/// <summary>
/// Represents a message returned by the OpenAI Assistants API.
/// </summary>
public class AssistantsMessage : ChatMessage
{
/// <summary>
/// The message contents from an assistants api response.
/// </summary>
public MessageContent MessageContent;

/// <summary>
/// Creates an AssistantMessage.
/// </summary>
/// <param name="content">The Assistants API thread message.</param>
public AssistantsMessage(MessageContent content) : base(ChatRole.Assistant)
{
this.MessageContent = content;

if (content != null)
{
string? textContent = content.Text;
if (content.Text != null && content.Text != string.Empty)
{
this.Content = content.Text;
}

MessageContext context = new();
for (int i = 0; i < content.TextAnnotations.Count; i++)
{
TextAnnotation annotation = content.TextAnnotations[i];
if (annotation?.TextToReplace != null)
{
textContent.Replace(annotation.TextToReplace, $"[{i}]");
}

if (annotation?.InputFileId != null)
{
// Retrieve file info object
// Neither `content` or `title` is provided in the annotations
context.Citations.Add(new("", "", annotation.InputFileId));
}

if (annotation?.OutputFileId != null)
{
// TODO: Download files or provide link to end user.
// Files were generated by code interpretor tool.
}
}

Context = context;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Bot.Builder;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Teams.AI.AI.Models;
using Microsoft.Teams.AI.Exceptions;
using Microsoft.Teams.AI.State;
using Microsoft.Teams.AI.Utilities;
Expand Down Expand Up @@ -52,7 +53,6 @@ public AssistantsPlanner(AssistantsPlannerOptions options, ILoggerFactory? logge
};
_logger = loggerFactory == null ? NullLogger.Instance : loggerFactory.CreateLogger<AssistantsPlanner<TState>>();
_client = _CreateClient(options.ApiKey, options.Endpoint);

}

/// <summary>
Expand Down Expand Up @@ -196,10 +196,8 @@ private async Task<Plan> _GeneratePlanFromMessagesAsync(string threadId, string
{
foreach (MessageContent content in message.Content)
{
if (content.Text != null)
{
plan.Commands.Add(new PredictedSayCommand(content.Text ?? string.Empty));
}
ChatMessage chatMessage = new AssistantsMessage(content);
plan.Commands.Add(new PredictedSayCommand(chatMessage));
}
}
return plan;
Expand Down

0 comments on commit c5dd283

Please sign in to comment.