forked from admin/VolcanicAgenticCore
fix(telegram): address review findings
- /resume discards the inbox once the id names one conversation, before any await - /stop discards input still waiting in the window - a forwarded message is never a command or a pending answer - ChatInbox.DrainAsync is an internal test helper - tests: /resume and /stop drop buffered text, forwarded /new is content, a failing flush doesn't stop later batches; no wall-clock sleep in the drain test - spec and user docs: timestamp exception for extension commands, command ordering, InputDebounce=0 wording
This commit is contained in:
@@ -46,6 +46,7 @@ public sealed class ChatCommands(TelegramSender sender)
|
||||
return true;
|
||||
|
||||
case "stop":
|
||||
chat.Inbox.Discard(); // what is still waiting in the window would start the run the user just stopped
|
||||
if (!session.IsStreaming && !session.IsCompacting)
|
||||
{
|
||||
await ReplyAsync(chat, "Nothing is running.", cancellationToken).ConfigureAwait(false);
|
||||
@@ -156,9 +157,9 @@ public sealed class ChatCommands(TelegramSender sender)
|
||||
var sessions = await chat.Session.ListSessionsAsync(cancellationToken).ConfigureAwait(false);
|
||||
var matches = sessions.Where(s => s.SessionId.StartsWith(id, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
if (matches.Count != 1) return matches.Count == 0 ? $"No conversation `{id}`." : $"`{id}` matches several conversations; use more characters.";
|
||||
chat.Inbox.Discard(); // what was typed before /resume belongs to neither conversation; drop it before it can flush
|
||||
if (chat.Session.IsStreaming) await chat.Session.AbortAsync().ConfigureAwait(false);
|
||||
var result = await chat.Session.SwitchSessionAsync(matches[0].SessionId, cancellationToken).ConfigureAwait(false);
|
||||
if (!result.Cancelled) chat.Inbox.Discard(); // what was typed before /resume belongs to the old conversation
|
||||
return result.Cancelled ? "An extension cancelled the switch." : $"Resumed `{matches[0].SessionId}` ({matches[0].MessageCount} messages).";
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,9 @@ public sealed class UpdateRouter(
|
||||
|
||||
var chat = await chats.GetAsync(message.Chat.Id, cancellationToken).ConfigureAwait(false);
|
||||
var text = message.Text ?? message.Caption ?? "";
|
||||
// Commands and pending answers are checked before the inbox, and only for messages without an attachment.
|
||||
if (!InboundComposer.HasAttachment(message))
|
||||
// Commands and pending answers are checked before the inbox, and only for messages without an attachment that
|
||||
// weren't forwarded: a forwarded message is content, never a command or an answer.
|
||||
if (!InboundComposer.HasAttachment(message) && message.ForwardOrigin is null)
|
||||
{
|
||||
if (ChatCommands.Parse(text) is not null)
|
||||
{
|
||||
@@ -78,8 +79,7 @@ public sealed class UpdateRouter(
|
||||
_ = chat.PromptInBackground(text);
|
||||
return;
|
||||
}
|
||||
// A forwarded message is content, not an answer.
|
||||
if (message.ForwardOrigin is null && chat.Ui.IsWaitingForInput && chat.Ui.TryResolveInput(text)) return;
|
||||
if (chat.Ui.IsWaitingForInput && chat.Ui.TryResolveInput(text)) return;
|
||||
}
|
||||
|
||||
// Take the lease now, in update order; compose (downloads) in the background so polling isn't blocked.
|
||||
|
||||
@@ -77,14 +77,14 @@ public sealed class ChatInbox : IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Drop buffered parts and in-flight leases (<c>/new</c>, <c>/resume</c>). Leases already open complete into nothing.</summary>
|
||||
/// <summary>Drop buffered parts and in-flight leases (<c>/new</c>, <c>/stop</c>, <c>/resume</c>). Leases already open complete into nothing.</summary>
|
||||
public void Discard()
|
||||
{
|
||||
lock (_lock) DropLocked();
|
||||
}
|
||||
|
||||
/// <summary>Completes when nothing is buffered, no lease is open and the last flush was handed over.</summary>
|
||||
public async Task DrainAsync()
|
||||
/// <summary>Completes when nothing is buffered, no lease is open and the last flush was handed over (test helper; polls).</summary>
|
||||
internal async Task DrainAsync()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user