Files
VolcanicAgenticCore/hosts/Volcanic.AgenticCore.Telegram/A2A/TelegramA2AResultDelivery.cs

46 lines
2.4 KiB
C#

using System.Globalization;
using Microsoft.Extensions.Logging;
using Volcanic.AgenticCore.Extensions.A2A;
using Volcanic.AgenticCore.Telegram.Chats;
namespace Volcanic.AgenticCore.Telegram.A2A;
/// <summary>
/// A2A watch results as follow-up prompts in the chat (target = chat id, invariant culture), like scheduled prompts:
/// never through the inbox. The chat's session is created on demand; <see cref="ChatRegistry.GetAsync"/> returns it only
/// once its renderer is subscribed, so the answer is always rendered. <see cref="WorkspaceFor"/> never creates a session.
/// </summary>
public sealed class TelegramA2AResultDelivery(ChatRegistry chats, ChatSettingsStore settings, TelegramOptions options, TimeProvider time,
ILogger<TelegramA2AResultDelivery> logger) : IA2AResultDelivery
{
private static bool TryChatIdOf(string target, out long chatId) =>
long.TryParse(target, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out chatId);
/// <summary>False (kept for later) for a target that isn't an allowed chat or whose session can't be opened.</summary>
public async Task<bool> DeliverAsync(string target, string text, CancellationToken cancellationToken)
{
if (!TryChatIdOf(target, out var chatId) || !options.IsAllowed(chatId)) return false;
var chat = await chats.GetAsync(chatId, cancellationToken).ConfigureAwait(false);
try
{
await ChatFollowUps.RunAsync(chat, text, settings.TimeZoneFor(chatId), time, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
throw;
}
catch (Exception ex)
{
// The prompt was handed to the session: delivered. The user sees why nothing came of it.
logger.LogError(ex, "A2A result in chat {ChatId} failed", chatId);
chat.Report($"An A2A result arrived but couldn't be processed: {ex.Message}");
}
return true;
}
public string? WorkspaceFor(string target) => TryChatIdOf(target, out var chatId) ? ChatRegistry.WorkspaceFor(options, chatId) : null;
/// <summary>Allowed chats only: a chat that left the allow-list keeps its pending.json untouched.</summary>
public IEnumerable<string> KnownTargets() => options.AllowedUserIds.Select(id => id.ToString(CultureInfo.InvariantCulture)).ToList();
}