Skip to content

Commit

Permalink
Merge pull request #1366 from solliancenet/aa-conversation-name-080
Browse files Browse the repository at this point in the history
0.8.0 - Add parameter to specify the conversation name when creating a new chat session
  • Loading branch information
ciprianjichici authored Aug 8, 2024
2 parents 1053c88 + 30f4f49 commit a8cf5b0
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 183 deletions.
16 changes: 16 additions & 0 deletions src/dotnet/Common/Models/Chat/ChatSessionProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;

namespace FoundationaLLM.Common.Models.Chat
{
/// <summary>
/// The session properties object.
/// </summary>
public class ChatSessionProperties
{
/// <summary>
/// The session name.
/// </summary>
[JsonPropertyName("name")]
public required string Name { get; set; }
}
}
15 changes: 4 additions & 11 deletions src/dotnet/Core/Interfaces/ICoreService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ public interface ICoreService
/// Creates a new chat session.
/// </summary>
/// <param name="instanceId">The instance Id.</param>
Task<Session> CreateNewChatSessionAsync(string instanceId);
/// <param name="chatSessionProperties">The session properties.</param>
Task<Session> CreateNewChatSessionAsync(string instanceId, ChatSessionProperties chatSessionProperties);

/// <summary>
/// Rename the chat session from its default (eg., "New Chat") to the summary provided by OpenAI.
/// </summary>
/// <param name="instanceId">The instance id.</param>
/// <param name="sessionId">The session id to rename.</param>
/// <param name="newChatSessionName">The new name for the chat session.</param>
Task<Session> RenameChatSessionAsync(string instanceId, string sessionId, string newChatSessionName);
/// <param name="chatSessionProperties">The session properties.</param>
Task<Session> RenameChatSessionAsync(string instanceId, string sessionId, ChatSessionProperties chatSessionProperties);

/// <summary>
/// Delete a chat session and related messages.
Expand All @@ -58,14 +59,6 @@ public interface ICoreService
/// <param name="directCompletionRequest">The completion request.</param>
Task<Completion> GetCompletionAsync(string instanceId, CompletionRequest directCompletionRequest);

/// <summary>
/// Generate a name for a chat message, based on the passed in prompt.
/// </summary>
/// <param name="instanceId">The instance id.</param>
/// <param name="sessionId">The session id to rename.</param>
/// <param name="text">The text to use when generating the name.</param>
Task<Completion> GenerateChatSessionNameAsync(string instanceId, string? sessionId, string? text);

/// <summary>
/// Rate an assistant message. This can be used to discover useful AI responses for training, discoverability, and other benefits down the road.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/dotnet/Core/Interfaces/ICosmosDbService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ public interface ICosmosDbService
/// Updates a session's name through a patch operation.
/// </summary>
/// <param name="id">The session id.</param>
/// <param name="name">The session's new name.</param>
/// <param name="sessionName">The session's new name.</param>
/// <param name="cancellationToken">Cancellation token for async calls.</param>
/// <returns>Revised chat session item.</returns>
Task<Session> UpdateSessionNameAsync(string id, string name, CancellationToken cancellationToken = default);
Task<Session> UpdateSessionNameAsync(string id, string sessionName, CancellationToken cancellationToken = default);

/// <summary>
/// Batch create or update chat messages and session.
Expand Down
32 changes: 7 additions & 25 deletions src/dotnet/Core/Services/CoreService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Azure.Core;
using FoundationaLLM.Common.Constants;
using FoundationaLLM.Common.Constants.ResourceProviders;
using FoundationaLLM.Common.Exceptions;
Expand Down Expand Up @@ -66,23 +65,26 @@ public async Task<List<Message>> GetChatSessionMessagesAsync(string instanceId,
}

/// <inheritdoc/>
public async Task<Session> CreateNewChatSessionAsync(string instanceId)
public async Task<Session> CreateNewChatSessionAsync(string instanceId, ChatSessionProperties chatSessionProperties)
{
ArgumentException.ThrowIfNullOrEmpty(chatSessionProperties.Name);

Session session = new()
{
Name = chatSessionProperties.Name,
Type = _sessionType,
UPN = _callContext.CurrentUserIdentity?.UPN ?? throw new InvalidOperationException("Failed to retrieve the identity of the signed in user when creating a new chat session.")
};
return await _cosmosDbService.InsertSessionAsync(session);
}

/// <inheritdoc/>
public async Task<Session> RenameChatSessionAsync(string instanceId, string sessionId, string newChatSessionName)
public async Task<Session> RenameChatSessionAsync(string instanceId, string sessionId, ChatSessionProperties chatSessionProperties)
{
ArgumentNullException.ThrowIfNull(sessionId);
ArgumentException.ThrowIfNullOrEmpty(newChatSessionName);
ArgumentException.ThrowIfNullOrEmpty(chatSessionProperties.Name);

return await _cosmosDbService.UpdateSessionNameAsync(sessionId, newChatSessionName);
return await _cosmosDbService.UpdateSessionNameAsync(sessionId, chatSessionProperties.Name);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -179,26 +181,6 @@ public Task<LongRunningOperation> GetCompletionOperationStatus(string instanceId
public async Task<CompletionResponse> GetCompletionOperationResult(string instanceId, string operationId) =>
throw new NotImplementedException();

/// <inheritdoc/>
public async Task<Completion> GenerateChatSessionNameAsync(string instanceId, string? sessionId, string? text)
{
try
{
ArgumentNullException.ThrowIfNull(sessionId);

var sessionName = string.Empty;
sessionName = $"{DateTime.UtcNow:yyyy-MM-dd HH:mm}";
await RenameChatSessionAsync(instanceId, sessionId, sessionName);

return new Completion { Text = sessionName };
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error generating session name for session {sessionId} for text [{text}].");
return new Completion { Text = "[No Name]" };
}
}

private IDownstreamAPIService GetDownstreamAPIService(AgentGatekeeperOverrideOption agentOption) =>
((agentOption == AgentGatekeeperOverrideOption.UseSystemOption) && _settings.BypassGatekeeper)
|| (agentOption == AgentGatekeeperOverrideOption.MustBypass)
Expand Down
4 changes: 2 additions & 2 deletions src/dotnet/Core/Services/CosmosDbService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,14 @@ public async Task<Session> UpdateSessionAsync(Session session, CancellationToken
}

/// <inheritdoc/>
public async Task<Session> UpdateSessionNameAsync(string id, string name, CancellationToken cancellationToken = default)
public async Task<Session> UpdateSessionNameAsync(string id, string sessionName, CancellationToken cancellationToken = default)
{
var response = await _sessions.PatchItemAsync<Session>(
id: id,
partitionKey: new PartitionKey(id),
patchOperations: new[]
{
PatchOperation.Set("/name", name),
PatchOperation.Set("/name", sessionName),
},
cancellationToken: cancellationToken
);
Expand Down
21 changes: 6 additions & 15 deletions src/dotnet/CoreAPI/Controllers/SessionsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,20 @@ public async Task<CompletionPrompt> GetCompletionPrompt(string instanceId, strin
/// Creates a new chat session.
/// </summary>
/// <param name="instanceId">The id of the instance.</param>
/// <param name="chatSessionProperties">The session properties.</param>
[HttpPost(Name = "CreateNewChatSession")]
public async Task<Session> CreateNewChatSession(string instanceId) =>
await _coreService.CreateNewChatSessionAsync(instanceId);
public async Task<Session> CreateNewChatSession(string instanceId, [FromBody] ChatSessionProperties chatSessionProperties) =>
await _coreService.CreateNewChatSessionAsync(instanceId, chatSessionProperties);

/// <summary>
/// Rename the chat session.
/// </summary>
/// <param name="instanceId">The id of the instance.</param>
/// <param name="sessionId">The id of the session to rename.</param>
/// <param name="newChatSessionName">The new name for the session.</param>
/// <param name="chatSessionProperties">The session properties.</param>
[HttpPost("{sessionId}/rename", Name = "RenameChatSession")]
public async Task<Session> RenameChatSession(string instanceId, string sessionId, string newChatSessionName) =>
await _coreService.RenameChatSessionAsync(instanceId, sessionId, newChatSessionName);
public async Task<Session> RenameChatSession(string instanceId, string sessionId, [FromBody] ChatSessionProperties chatSessionProperties) =>
await _coreService.RenameChatSessionAsync(instanceId, sessionId, chatSessionProperties);

/// <summary>
/// Delete a chat session and related messages.
Expand All @@ -90,15 +91,5 @@ public async Task<Session> RenameChatSession(string instanceId, string sessionId
[HttpDelete("{sessionId}", Name = "DeleteChatSession")]
public async Task DeleteChatSession(string instanceId, string sessionId) =>
await _coreService.DeleteChatSessionAsync(instanceId, sessionId);

/// <summary>
/// Generate a name for a chat message, based on the passed in prompt.
/// </summary>
/// <param name="instanceId">The id of the instance.</param>
/// <param name="sessionId">The id of the session for which to generate a name.</param>
/// <param name="text">The prompt to use to generate the name.</param>
[HttpPost("{sessionId}/generate-name", Name = "GenerateChatSessionName")]
public async Task<Completion> GenerateChatSessionName(string instanceId, string sessionId, [FromBody] string text) =>
await _coreService.GenerateChatSessionNameAsync(instanceId, sessionId, text);
}
}
20 changes: 12 additions & 8 deletions src/dotnet/CoreClient/Clients/RESTClients/SessionRESTClient.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using Azure.Core;
using Azure.Core;
using FoundationaLLM.Client.Core.Interfaces;
using FoundationaLLM.Common.Models.Chat;
using System.Net.Http.Json;
using System.Text.Json;

namespace FoundationaLLM.Client.Core.Clients.RESTClients
{
Expand All @@ -17,10 +17,12 @@ internal class SessionRESTClient(
private readonly string _instanceId = instanceId ?? throw new ArgumentNullException(nameof(instanceId));

/// <inheritdoc/>
public async Task<string> CreateSessionAsync()
public async Task<string> CreateSessionAsync(ChatSessionProperties chatSessionProperties)
{
var coreClient = await GetCoreClientAsync();
var responseSession = await coreClient.PostAsync($"instances/{_instanceId}/sessions", null);
var responseSession = await coreClient.PostAsync(
$"instances/{_instanceId}/sessions",
JsonContent.Create(chatSessionProperties));

if (responseSession.IsSuccessStatusCode)
{
Expand All @@ -36,14 +38,16 @@ public async Task<string> CreateSessionAsync()
}

/// <inheritdoc/>
public async Task<string> RenameChatSession(string sessionId, string sessionName)
public async Task<string> RenameChatSession(string sessionId, ChatSessionProperties chatSessionProperties)
{
var coreClient = await GetCoreClientAsync();
var response = await coreClient.PostAsync($"instances/{_instanceId}/sessions/{sessionId}/rename?newChatSessionName={UrlEncoder.Default.Encode(sessionName)}", null);
var response = await coreClient.PostAsync(
$"instances/{_instanceId}/sessions/{sessionId}/rename",
JsonContent.Create(chatSessionProperties));

if (response.IsSuccessStatusCode)
{
return sessionName;
return chatSessionProperties.Name;
}

throw new Exception($"Failed to rename chat session. Status code: {response.StatusCode}. Reason: {response.ReasonPhrase}");
Expand Down
33 changes: 23 additions & 10 deletions src/dotnet/CoreClient/CoreClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,29 @@ public CoreClient(
_coreRestClient = new CoreRESTClient(coreUri, credential, instanceId, options);

/// <inheritdoc/>
public async Task<string> CreateChatSessionAsync(string? sessionName)
public async Task<string> CreateChatSessionAsync(ChatSessionProperties chatSessionProperties)
{
var sessionId = await _coreRestClient.Sessions.CreateSessionAsync();
if (!string.IsNullOrWhiteSpace(sessionName))
{
await _coreRestClient.Sessions.RenameChatSession(sessionId, sessionName);
}
if (string.IsNullOrWhiteSpace(chatSessionProperties.Name))
throw new ArgumentException("A session name must be provided when creating a new session.");

var sessionId = await _coreRestClient.Sessions.CreateSessionAsync(chatSessionProperties);
return sessionId;
}

/// <inheritdoc/>
public async Task<Completion> GetCompletionWithSessionAsync(string? sessionId, string? sessionName,
public async Task<Completion> GetCompletionWithSessionAsync(string? sessionId, ChatSessionProperties? chatSessionProperties,
string userPrompt, string agentName)
{
if (string.IsNullOrWhiteSpace(sessionId))
{
sessionId = await CreateChatSessionAsync(sessionName);
if (chatSessionProperties == null)
{
throw new ArgumentException(
"The completion request must contain a session name if no session Id is provided. " +
"A new session will be created with the provided session name.");
}

sessionId = await CreateChatSessionAsync(chatSessionProperties);
}

var orchestrationRequest = new CompletionRequest
Expand All @@ -81,6 +86,7 @@ public async Task<Completion> GetCompletionWithSessionAsync(string? sessionId, s
SessionId = sessionId,
UserPrompt = userPrompt
};

return await GetCompletionWithSessionAsync(orchestrationRequest);
}

Expand Down Expand Up @@ -126,7 +132,7 @@ public async Task<Completion> GetCompletionAsync(CompletionRequest completionReq

/// <inheritdoc/>
public async Task<Completion> AttachFileAndAskQuestionAsync(Stream fileStream, string fileName, string contentType,
string agentName, string question, bool useSession, string? sessionId, string? sessionName)
string agentName, string question, bool useSession, string? sessionId, ChatSessionProperties? chatSessionProperties)
{
if (fileStream == null)
{
Expand All @@ -139,7 +145,14 @@ public async Task<Completion> AttachFileAndAskQuestionAsync(Stream fileStream, s
{
if (string.IsNullOrWhiteSpace(sessionId))
{
sessionId = await CreateChatSessionAsync(sessionName);
if (chatSessionProperties == null)
{
throw new ArgumentException(
"The completion request must contain a session name if no session Id is provided. " +
"A new session will be created with the provided session name.");
}

sessionId = await CreateChatSessionAsync(chatSessionProperties);
}

var orchestrationRequest = new CompletionRequest
Expand Down
14 changes: 7 additions & 7 deletions src/dotnet/CoreClient/Interfaces/ICoreClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ namespace FoundationaLLM.Client.Core.Interfaces
public interface ICoreClient
{
/// <summary>
/// Creates a new chat session and renames it if a session name is provided.
/// Creates a new chat session with the specified name.
/// </summary>
/// <param name="sessionName">Renames the new chat session if not null or empty.</param>
/// <param name="sessionProperties">The session properties.</param>
/// <returns>The new chat session ID.</returns>
Task<string> CreateChatSessionAsync(string? sessionName);
Task<string> CreateChatSessionAsync(ChatSessionProperties sessionProperties);

/// <summary>
/// Runs a single completion request with an agent using the Core API and a chat session.
Expand All @@ -25,12 +25,12 @@ public interface ICoreClient
/// </summary>
/// <param name="sessionId">The ID of an existing session. If null or empty, a new session
/// is created first.</param>
/// <param name="sessionName">Renames the new chat session if not null or empty.</param>
/// <param name="sessionProperties">Optional session priperties.</param>
/// <param name="userPrompt">The user prompt to send to the agent.</param>
/// <param name="agentName">The name of the FoundationaLLM agent that will handle the
/// completion request.</param>
/// <returns>A completion from the designated FoundationaLLM agent.</returns>
Task<Completion> GetCompletionWithSessionAsync(string? sessionId, string? sessionName,
Task<Completion> GetCompletionWithSessionAsync(string? sessionId, ChatSessionProperties? sessionProperties,
string userPrompt, string agentName);

/// <summary>
Expand Down Expand Up @@ -83,11 +83,11 @@ Task<Completion> GetCompletionWithSessionAsync(string? sessionId, string? sessio
/// false, no session is created and the sessionless orchestration flow is used.</param>
/// <param name="sessionId">The ID of an existing session. If null or empty, a new session
/// is created first.</param>
/// <param name="sessionName">Renames the new chat session if not null or empty.</param>
/// <param name="chatSessionProperties">Optional session properties.</param>
/// <returns>A completion from the designated FoundationaLLM agent.</returns>
/// <returns>A completion from the designated FoundationaLLM agent.</returns>
Task<Completion> AttachFileAndAskQuestionAsync(Stream fileStream, string fileName, string contentType,
string agentName, string question, bool useSession, string? sessionId, string? sessionName);
string agentName, string question, bool useSession, string? sessionId, ChatSessionProperties? chatSessionProperties);

/// <summary>
/// Returns the chat messages related to an existing session.
Expand Down
10 changes: 5 additions & 5 deletions src/dotnet/CoreClient/Interfaces/ISessionRESTClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using FoundationaLLM.Common.Models.Chat;
using FoundationaLLM.Common.Models.Orchestration;

namespace FoundationaLLM.Client.Core.Interfaces
{
Expand All @@ -24,18 +23,19 @@ public interface ISessionRESTClient
Task RateMessageAsync(string sessionId, string messageId, bool rating);

/// <summary>
/// Creates and renames a session.
/// Creates a new session with the specified name.
/// </summary>
/// <param name="chatSessionProperties">The session properties.</param>
/// <returns>Returns the new Session ID.</returns>
Task<string> CreateSessionAsync();
Task<string> CreateSessionAsync(ChatSessionProperties chatSessionProperties);

/// <summary>
/// Renames a chat session.
/// </summary>
/// <param name="sessionId">The chat session ID.</param>
/// <param name="sessionName">The new session name.</param>
/// <param name="chatSessionProperties">The session properties.</param>
/// <returns></returns>
Task<string> RenameChatSession(string sessionId, string sessionName);
Task<string> RenameChatSession(string sessionId, ChatSessionProperties chatSessionProperties);

/// <summary>
/// Gets a completion prompt by session ID and completion prompt ID.
Expand Down
Loading

0 comments on commit a8cf5b0

Please sign in to comment.