Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #22 #23

Merged
merged 3 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions ChatRoom/ChatRoom.Client/AgentExtensionBootstrapService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public async Task StartAsync(CancellationToken cancellationToken)
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();

_logger.LogInformation("Extension {ExtensionName} started with pid {PID}", extension.Name, process.Id);
}
catch (Exception ex)
{
Expand All @@ -52,6 +54,8 @@ public async Task StopAsync(CancellationToken cancellationToken)
{
process.Kill();
await process.WaitForExitAsync();

_logger.LogInformation("Extension {ExtensionName} stopped", process.Id);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -82,15 +86,15 @@ public Process CreateExtensionProcess(AgentExtensionConfiguration configuration)
{
if (args.Data is not null)
{
_logger.LogInformation("Extension {ExtensionName} output: {Output}", configuration.Name, args.Data);
_logger.LogInformation("Extension {ExtensionName} (pid: {PID}) output: {Output}", configuration.Name, process.Id , args.Data);
}
};

process.ErrorDataReceived += (sender, args) =>
{
if (args.Data is not null)
{
_logger.LogError("Extension {ExtensionName} error: {Error}", configuration.Name, args.Data);
_logger.LogError("Extension {ExtensionName} (pid: {PID}) error: {Error}", configuration.Name, process.Id, args.Data);
}
};

Expand Down
23 changes: 21 additions & 2 deletions ChatRoom/ChatRoom.Client/ChatRoomClientCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,30 @@ public override async Task<int> ExecuteAsync(CommandContext context, ChatRoomCli
logger.LogInformation($"Workspace: {workspace}");
logger.LogInformation($"client log is saved to: {Path.Combine(workspace, "logs", clientLogPath)}");
AnsiConsole.MarkupLine("[bold green]Client started.[/]");
var lifetimeManager = sp.GetRequiredService<IHostApplicationLifetime>();

await AnsiConsole.Status()
.StartAsync("initializing...", async ctx =>
{
ctx.Spinner(Spinner.Known.Dots);

do
{
await Task.Delay(1000);
}
while (!lifetimeManager.ApplicationStarted.IsCancellationRequested);
});
var consoleChatRoomService = sp.GetRequiredService<ConsoleChatRoomService>();
await consoleChatRoomService.StartAsync(CancellationToken.None);

await host.StopAsync();
await host.WaitForShutdownAsync();
await AnsiConsole.Status()
.StartAsync("shutting down...", async ctx =>
{
ctx.Spinner(Spinner.Known.Dots);
await host.StopAsync();
await host.WaitForShutdownAsync();
});

return 0;
}
}
62 changes: 62 additions & 0 deletions ChatRoom/ChatRoom.Client/ChatRoomContextSchemaV0.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace ChatRoom.Client;

public abstract class Schema
{
[JsonPropertyName("type")]
public abstract string SchemaType { get; }
}

public class ChatRoomContextSchemaV0 : Schema
{
[JsonPropertyName("type")]
public override string SchemaType => nameof(ChatRoomContextSchemaV0);

[JsonPropertyName("channels")]
public Dictionary<string, string[]> Channels { get; set; } = new();

[JsonPropertyName("chat_history")]
public Dictionary<string, ChatMsg[]> ChatHistory { get; set; } = new();

[JsonPropertyName("current_channel")]
public string CurrentChannel { get; set; } = "General";
}

public class ChatRoomContext
{
public ChatRoomContext(ChatRoomContextSchemaV0 workspaceSchemaV0)
{
this.ChatHistory = workspaceSchemaV0.ChatHistory;
this.Channels = workspaceSchemaV0.Channels;
this.CurrentChannel = workspaceSchemaV0.CurrentChannel;
}

public ChatRoomContext()
{
this.ChatHistory = new();
this.Channels = new();
this.CurrentChannel = "General";
}

public Dictionary<string, string[]> Channels { get; set; }

public Dictionary<string, ChatMsg[]> ChatHistory { get; set; }

public string CurrentChannel { get; set; } = "General";

public ChatRoomContextSchemaV0 ToSchema()
{
return new ChatRoomContextSchemaV0
{
Channels = this.Channels,
ChatHistory = this.ChatHistory,
CurrentChannel = this.CurrentChannel
};
}
}
85 changes: 75 additions & 10 deletions ChatRoom/ChatRoom.Client/ConsoleChatRoomService.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
using System.Reflection;
using System.Text.Json;
using ChatRoom.Common;
using Microsoft.Extensions.Hosting;
using Orleans.Runtime;
using Microsoft.Extensions.Logging;
using Spectre.Console;

namespace ChatRoom.Client;

public class ConsoleChatRoomService : IHostedService
public class ConsoleChatRoomService
{
private readonly IClusterClient _clusterClient;
private readonly ClientContext _clientContext;
private ClientContext _clientContext;
private readonly ConsoleRoomObserver _roomObserver;
private readonly IRoomObserver _roomObserverRef;

public ConsoleChatRoomService(ChatRoomClientConfiguration configuration, IClusterClient clsterClient)
private readonly ILogger _logger;
private readonly string _workspacePath = null!;
private readonly string _chatRoomContextSchemaPath = null!;

public ConsoleChatRoomService(
ChatRoomClientConfiguration configuration,
IClusterClient clsterClient,
ILogger<ConsoleChatRoomService> logger)
{
_logger = logger;
_workspacePath = configuration.Workspace;
_chatRoomContextSchemaPath = Path.Combine(_workspacePath, "chat-history.json");
_roomObserver = new ConsoleRoomObserver();
_roomObserverRef = clsterClient.CreateObjectReference<IRoomObserver>(_roomObserver);
_clusterClient = clsterClient;
Expand All @@ -26,10 +34,29 @@ public async Task StartAsync(CancellationToken cancellationToken)
PrintUsage();
var room = _clientContext.ChannelClient.GetGrain<IRoomGrain>(_clientContext.CurrentRoom);
await room.JoinRoom(_clientContext.UserName!, _clientContext.Description!, true, _roomObserverRef);

// restore previous state
if (File.Exists(_chatRoomContextSchemaPath))
{
AnsiConsole.MarkupLine("[bold red]Restoring workspace from {0}[/]", _workspacePath);
var schema = JsonSerializer.Deserialize<ChatRoomContextSchemaV0>(File.ReadAllText(_chatRoomContextSchemaPath))!;
var workspaceConfiguration = new ChatRoomContext(schema);
foreach (var channel in workspaceConfiguration.Channels)
{
var channelName = channel.Key;
var channelMembers = channel.Value;
var channelHistory = workspaceConfiguration.ChatHistory.TryGetValue(channelName, out var history) ? history : null;
await room.CreateChannel(channelName, channelMembers, channelHistory);
_logger.LogInformation("Restored channel {ChannelName} with {MemberCount} members and {HistoryCount} history items", channelName, channelMembers.Count(), channelHistory?.Count() ?? 0);
}

_clientContext = _clientContext with { CurrentChannel = workspaceConfiguration.CurrentChannel };
}

await JoinChannel(_clientContext, _clientContext.CurrentChannel!);
await ProcessLoopAsync(_clientContext, cancellationToken);
}

public async Task StopAsync(CancellationToken cancellationToken)
{
//_processTask?.Wait();
Expand All @@ -50,6 +77,11 @@ async Task ProcessLoopAsync(ClientContext context, CancellationToken ct)
if (input.StartsWith("/exit") &&
AnsiConsole.Confirm("Do you really want to exit?"))
{
if (AnsiConsole.Confirm("Do you want to save the workspace?"))
{
await SaveContextToWorkspace(context);
}

break;
}

Expand Down Expand Up @@ -110,7 +142,7 @@ async Task ProcessLoopAsync(ClientContext context, CancellationToken ct)
AnsiConsole.MarkupLine("[bold red]Member '{0}' already exists in the channel[/]", memberName);
continue;
}

await room.AddAgentToChannel(channelInfo, memberName);
continue;
}
Expand Down Expand Up @@ -159,13 +191,16 @@ async Task ProcessLoopAsync(ClientContext context, CancellationToken ct)
{
"/h" => ShowCurrentChannelHistory(context),
"/m" => ShowChannelMembers(context),
"/s" => SaveContextToWorkspace(context),
_ => null
} is Task task)
{
await task;
continue;
}



if (context.IsConnectedToChannel)
{
await SendMessage(context, input);
Expand Down Expand Up @@ -197,6 +232,7 @@ private void PrintUsage()
+ "[bold fuchsia]/l[/] to [underline green]leave[/] the current channel\n"
+ "[bold fuchsia]/h[/] to re-read channel [underline green]history[/]\n"
+ "[bold fuchsia]/m[/] to query [underline green]members[/] in the current channel\n"
+ "[bold fuchsia]/s[/] to save the channel information and history to the workspace\n"
+ "[bold fuchsia]/lm[/] to query [underline green]members[/] in the room\n"
+ "[bold fuchsia]/lc[/] to query [underline green]all channels[/] in the room\n"
+ "[bold fuchsia]/rc[/] [aqua]<channel>[/] to [underline green]remove channel[/] from the room\n"
Expand All @@ -222,6 +258,35 @@ private void PrintUsage()
AnsiConsole.WriteLine();
}

private async Task SaveContextToWorkspace(ClientContext context)
{
var room = context.ChannelClient.GetGrain<IRoomGrain>(context.CurrentRoom);
var channels = await room.GetChannels();
Dictionary<string, ChatMsg[]> chatHistory = new();
Dictionary<string, string[]> channelMembers = new();
foreach (var channel in channels)
{
var channelGrain = context.ChannelClient.GetGrain<IChannelGrain>(channel.Name);
var history = await channelGrain.ReadHistory(100);
chatHistory[channel.Name] = history.ToArray();
var members = await channelGrain.GetMembers();
channelMembers[channel.Name] = members.Select(m => m.Name).ToArray();
}

var workspaceConfiguration = new ChatRoomContext
{
Channels = channelMembers,
ChatHistory = chatHistory,
CurrentChannel = context.CurrentChannel!,
};

var schema = workspaceConfiguration.ToSchema();
var json = JsonSerializer.Serialize(schema, new JsonSerializerOptions { WriteIndented = true });

_logger.LogInformation("Saving workspace to {WorkspacePath}", _workspacePath);
AnsiConsole.MarkupLine("[bold red]Saving workspace to {0}[/]", _workspacePath);
await File.WriteAllTextAsync(_chatRoomContextSchemaPath, json);
}

private async Task ShowChannelMembers(ClientContext context)
{
Expand Down Expand Up @@ -355,7 +420,7 @@ private async Task<ClientContext> JoinChannel(
await AnsiConsole.Status().StartAsync("Joining channel...", async ctx =>
{
var room = context.ChannelClient.GetGrain<IRoomGrain>(context.CurrentRoom);
await room.CreateChannel(new ChannelInfo(channelName));
await room.CreateChannel(channelName);
var channel = context.ChannelClient.GetGrain<IChannelGrain>(context.CurrentChannel);
await channel.JoinChannel(context.UserName!, "Human user", true, _roomObserverRef);
});
Expand Down
1 change: 1 addition & 0 deletions ChatRoom/ChatRoom.Common/ChatRoom.SDK.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<ItemGroup>
<InternalsVisibleTo Include="ChatRoom.Room"/>
<InternalsVisibleTo Include="ChatRoom.Client"/>
<InternalsVisibleTo Include="ChatRoom.Tests"/>
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions ChatRoom/ChatRoom.Common/IChannelGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public interface IChannelGrain : IOrchestratorGrain, IGrainWithStringKey

Task LeaveChannel(string name);

internal Task InitializeChatHistory(ChatMsg[] history);

internal Task<bool> Message(ChatMsg msg);

internal Task<ChatMsg[]> ReadHistory(int numberOfMessages);
Expand Down
2 changes: 1 addition & 1 deletion ChatRoom/ChatRoom.Common/IRoomGrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface IRoomGrain : IGrainWithStringKey

Task<ChannelInfo[]> GetChannels();

Task CreateChannel(ChannelInfo channelInfo);
Task CreateChannel(string channelName, string[]? members = null, ChatMsg[]? chatHistory = null);

Task DeleteChannel(string channelName);

Expand Down
Loading