fix: make dave telegram alerts conversational
This commit is contained in:
@@ -150,10 +150,10 @@ export class TelegramAlerter {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
_conversationChunks(text, maxLen = 900) {
|
||||
_conversationChunks(text, maxLen = 420) {
|
||||
const cleaned = stripVisibleMarkdown(String(text || '').trim());
|
||||
if (!cleaned) return [];
|
||||
const limit = Math.max(300, Math.min(1800, Number(maxLen) || 900));
|
||||
const limit = Math.max(160, Math.min(900, Number(maxLen) || 420));
|
||||
const paragraphs = cleaned.split(/\n{2,}/).map(part => part.trim()).filter(Boolean);
|
||||
const chunks = [];
|
||||
let current = '';
|
||||
@@ -163,21 +163,19 @@ export class TelegramAlerter {
|
||||
};
|
||||
|
||||
for (const paragraph of paragraphs) {
|
||||
if (paragraph.length > limit) {
|
||||
flush();
|
||||
for (const sentence of splitSentences(paragraph)) {
|
||||
if ((current.length + sentence.length + 1) > limit) flush();
|
||||
if (sentence.length > limit) {
|
||||
chunks.push(...this._chunkText(sentence, limit).map(part => part.trim()).filter(Boolean));
|
||||
} else {
|
||||
current = current ? `${current} ${sentence}` : sentence;
|
||||
}
|
||||
const sentences = splitSentences(paragraph);
|
||||
const shouldSentenceSplit = paragraph.length > Math.floor(limit * 0.65) || sentences.length > 2;
|
||||
const units = shouldSentenceSplit ? sentences : [paragraph];
|
||||
|
||||
for (const unit of units) {
|
||||
if (unit.length > limit) {
|
||||
flush();
|
||||
chunks.push(...this._chunkText(unit, limit).map(part => part.trim()).filter(Boolean));
|
||||
continue;
|
||||
}
|
||||
flush();
|
||||
continue;
|
||||
if ((current.length + unit.length + 2) > limit) flush();
|
||||
current = current ? `${current}\n\n${unit}` : unit;
|
||||
}
|
||||
if ((current.length + paragraph.length + 2) > limit) flush();
|
||||
current = current ? `${current}\n\n${paragraph}` : paragraph;
|
||||
}
|
||||
flush();
|
||||
return chunks;
|
||||
@@ -195,7 +193,7 @@ export class TelegramAlerter {
|
||||
* Evaluate delta signals with LLM and send tiered alert if warranted.
|
||||
* Uses semantic dedup, rate limiting, and a much richer evaluation prompt.
|
||||
*/
|
||||
async evaluateAndAlert(llmProvider, delta, memory) {
|
||||
async evaluateAndAlert(llmProvider, delta, memory, opts = {}) {
|
||||
if (!this.isConfigured) return false;
|
||||
if (!delta?.summary?.totalChanges) return false;
|
||||
if (this._isMuted()) {
|
||||
@@ -262,9 +260,13 @@ export class TelegramAlerter {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. Format and send tiered alert
|
||||
const message = this._formatTieredAlert(evaluation, delta, tier);
|
||||
const sent = await this.sendAlert(message);
|
||||
// 4. Format and send as short conversational messages.
|
||||
const messages = this._formatTieredAlertConversation(evaluation, delta, tier, opts);
|
||||
const sendResult = await this.sendConversation(messages, {
|
||||
maxChunkChars: opts.maxChunkChars ?? 360,
|
||||
delayMs: opts.delayMs ?? 450,
|
||||
});
|
||||
const sent = Boolean(sendResult?.ok || sendResult === true);
|
||||
|
||||
if (sent) {
|
||||
// Mark signals as alerted with content hashing
|
||||
@@ -963,6 +965,50 @@ Respond with ONLY valid JSON:
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
_formatTieredAlertConversation(evaluation, delta, tier, opts = {}) {
|
||||
const german = normalizeLanguage(opts.language) === 'de';
|
||||
const tierLabel = german
|
||||
? ({ FLASH: 'SOFORT', PRIORITY: 'PRIO', ROUTINE: 'HINWEIS' }[tier] || 'HINWEIS')
|
||||
: ({ FLASH: 'NOW', PRIORITY: 'PRIORITY', ROUTINE: 'NOTE' }[tier] || 'NOTE');
|
||||
const confidence = String(evaluation.confidence || 'MEDIUM').toLowerCase();
|
||||
const direction = String(delta?.summary?.direction || 'mixed').toLowerCase();
|
||||
const headline = compactLine(evaluation.headline || (german ? 'Neue relevante Aenderung erkannt.' : 'New relevant change detected.'));
|
||||
const reason = compactLine(evaluation.reason || '');
|
||||
const signals = Array.isArray(evaluation.signals) ? evaluation.signals.map(compactLine).filter(Boolean).slice(0, 2) : [];
|
||||
|
||||
const messages = [
|
||||
`[DAVE // ${tierLabel}]\n${headline}`,
|
||||
];
|
||||
|
||||
if (reason && reason !== headline) {
|
||||
messages.push(reason);
|
||||
}
|
||||
|
||||
if (tier !== 'ROUTINE' || confidence !== 'low') {
|
||||
messages.push(german
|
||||
? `Einordnung: ${confidence}, Richtung ${direction}.`
|
||||
: `Read: ${confidence} confidence, ${direction} direction.`);
|
||||
}
|
||||
|
||||
if (signals.length) {
|
||||
messages.push(german
|
||||
? `Ich sehe vor allem: ${signals.join('; ')}.`
|
||||
: `Main signals: ${signals.join('; ')}.`);
|
||||
}
|
||||
|
||||
if (evaluation.actionable && evaluation.actionable !== 'Monitor') {
|
||||
messages.push(german
|
||||
? `Naechster sinnvoller Schritt: ${compactLine(evaluation.actionable)}`
|
||||
: `Useful next step: ${compactLine(evaluation.actionable)}`);
|
||||
} else {
|
||||
messages.push(german
|
||||
? 'Soll ich das genauer auseinandernehmen?'
|
||||
: 'Want me to dig into it?');
|
||||
}
|
||||
|
||||
return messages.filter(Boolean);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────
|
||||
@@ -1008,6 +1054,20 @@ function splitSentences(text) {
|
||||
return normalized.match(/[^.!?\n]+[.!?]+(?:\s+|$)|[^.!?\n]+$/g)?.map(item => item.trim()).filter(Boolean) || [normalized];
|
||||
}
|
||||
|
||||
function normalizeLanguage(value) {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
return normalized === 'de' || normalized === 'en' ? normalized : null;
|
||||
}
|
||||
|
||||
function compactLine(value, maxLen = 320) {
|
||||
const cleaned = stripVisibleMarkdown(String(value || ''))
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/^[-*]\s*/, '')
|
||||
.trim();
|
||||
if (cleaned.length <= maxLen) return cleaned;
|
||||
return `${cleaned.slice(0, maxLen - 1).trim()}...`;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user