feat: persistent typing indicator — refreshes every 4s until first stream token

This commit is contained in:
admin
2026-05-05 18:46:32 +00:00
Unverified
parent eb158ce089
commit 145f49b28a
2 changed files with 26 additions and 2 deletions

6
memories.md Normal file
View File

@@ -0,0 +1,6 @@
### Self-Challenge Results (2025-07-09)
- Demonstrated full self-challenge loop: write code → write tests → run tests → all pass ✅
- 10/10 tests passed on math_utils.py (fibonacci, is_prime, factorial)
- Python 3.12 available at /usr/bin/python3, pytest 9.0.2 pre-installed

View File

@@ -1026,8 +1026,15 @@ export async function initBot(config, api, tools, skills, agents) {
logger.info(`${prefix} ${user}: ${text.substring(0, 80)}`); logger.info(`${prefix} ${user}: ${text.substring(0, 80)}`);
await queueRequest(key, text, async () => { await queueRequest(key, text, async () => {
await ctx.api.sendChatAction(ctx.chat.id, 'typing'); // ── Typing indicator: keep pinging until first stream token arrives ──
let firstTokenArrived = false;
const typingInterval = setInterval(async () => {
if (firstTokenArrived) return;
try { await ctx.api.sendChatAction(ctx.chat.id, 'typing'); } catch {}
}, 4000); // Telegram typing expires after 5s, refresh every 4s
await ctx.api.sendChatAction(ctx.chat.id, 'typing'); // initial ping
try {
// ── Load conversation history for this chat ── // ── Load conversation history for this chat ──
const chatKey = conversation._key(ctx.chat.id, ctx.message?.message_thread_id); const chatKey = conversation._key(ctx.chat.id, ctx.message?.message_thread_id);
svc.currentChatId = ctx.chat.id; // Track for TTS auto-send svc.currentChatId = ctx.chat.id; // Track for TTS auto-send
@@ -1046,7 +1053,10 @@ export async function initBot(config, api, tools, skills, agents) {
// Wrap chatWithAI with self-correction + streaming // Wrap chatWithAI with self-correction + streaming
const chatWithCorrection = withSelfCorrection(async (msgs) => { const chatWithCorrection = withSelfCorrection(async (msgs) => {
return await chatWithAI(msgs, { onDelta: (token) => consumer.onDelta(token) }); return await chatWithAI(msgs, { onDelta: (token) => {
if (!firstTokenArrived) firstTokenArrived = true;
consumer.onDelta(token);
}});
}); });
const result = await chatWithCorrection(messages); const result = await chatWithCorrection(messages);
@@ -1055,6 +1065,10 @@ export async function initBot(config, api, tools, skills, agents) {
await conversation.add(chatKey, 'user', text); await conversation.add(chatKey, 'user', text);
if (result) await conversation.add(chatKey, 'assistant', result); if (result) await conversation.add(chatKey, 'assistant', result);
// Stop typing indicator
firstTokenArrived = true;
clearInterval(typingInterval);
// Signal completion and wait for final edit // Signal completion and wait for final edit
consumer.finish(); consumer.finish();
await runPromise; await runPromise;
@@ -1069,6 +1083,10 @@ export async function initBot(config, api, tools, skills, agents) {
// ── Self-learning: extract patterns from this interaction ── // ── Self-learning: extract patterns from this interaction ──
await selfLearn(text, result, memory); await selfLearn(text, result, memory);
} finally {
// Always stop typing indicator, even on error
clearInterval(typingInterval);
}
}); });
} }