V13 / 7879e8b5740b
Lilith.Chat.cs
Lilith/Agent/Lilith.Chat.cs
Unchanged from the preceding versionCS
using Lilith.Core.Logging;
using Lilith.Core.Ollama;
using Lilith.Core.Providers;
using System.Diagnostics;
namespace Lilith.Agent;
public partial class Lilith
{
public async Task ChatAsync(string input, List<string>? images = null, CancellationToken cancellationToken = default)
{
using var operation = await _operation.EnterAsync(cancellationToken);
ObjectDisposedException.ThrowIf(_disposed, this);
if (!IsBooted) throw new InvalidOperationException("Boot the agent before chatting.");
await ChatCoreAsync(input, images, cancellationToken);
}
private async Task ChatCoreAsync(string input, List<string>? images = null, CancellationToken cancellationToken = default)
{
var timer = Stopwatch.StartNew();
string reply;
try { reply = await Client.StreamReply(input, images, cancellationToken); }
finally { timer.Stop(); }
this.LogTokenCounts(timer.Elapsed);
await SpeakReplyAsync(reply, cancellationToken);
}
private T WithConversation<T>(Func<ProviderClient, T> action)
{
using var operation = EnterOperation("Boot the agent before using its conversation.");
return action(Client);
}
private void WithConversation(Action<ProviderClient> action)
{
using var operation = EnterOperation("Boot the agent before using its conversation.");
action(Client);
}
public void NewConversation() => WithConversation(client => client.NewConversation());
public async Task ApproveWorkspaceAsync(string id, CancellationToken cancellationToken = default)
{
using var operation = EnterOperation("Boot before approving workspace changes.");
string reply = await Client.ApproveWorkspaceAsync(id, cancellationToken);
await SpeakReplyAsync(reply, cancellationToken);
}
public async Task RejectWorkspaceAsync(string id, CancellationToken cancellationToken = default)
{
using var operation = EnterOperation("Boot before rejecting workspace changes.");
var result = await Workspace.ExecuteAsync(new("reject", BinId: id), cancellationToken);
Logger.SystemWriteLine(result.Message);
}
public void SaveConversation() => WithConversation(client => client.SaveConversation());
public IReadOnlyList<ChatSessionSummary> ListConversations() => WithConversation(client => client.ListConversations());
public bool LoadConversation(int displayIndex) => WithConversation(client => client.LoadConversation(displayIndex));
public bool LoadConversation(string id) => WithConversation(client => client.LoadConversation(id));
public void HandleHistoryCommand(string input)
{
var parts = input.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (parts.Length == 1)
{
var sessions = ListConversations();
if (sessions.Count == 0)
{
Logger.HistoryWriteLine("No saved chats found.");
return;
}
Logger.HistoryWriteLine("Saved chats:", LogColors.Cyan);
for (int i = 0; i < sessions.Count; i++)
{
var session = sessions[i];
Logger.HistoryWriteLine($"{i + 1}. {session.Title} ({session.UpdatedAt.LocalDateTime:g}, {session.MessageCount} messages)");
}
Logger.HistoryWriteLine("Use /history <number> to load a chat.");
return;
}
if (!int.TryParse(parts[1], out int index))
{
Logger.HistoryWriteLine("Usage: /history or /history <number>", LogColors.Orange);
return;
}
if (LoadConversation(index))
{
Logger.HistoryWriteLine($"Loaded saved chat #{index}.", LogColors.Cyan);
}
else
{
Logger.HistoryWriteLine($"Saved chat #{index} was not found.", LogColors.Orange);
}
}
}