// Default heartbeat prompt (used when config.agents.defaults.heartbeat.prompt is unset). // Keep it tight and avoid encouraging the model to invent/rehash "open loops" from prior chat context.
export const HEARTBEAT_PROMPT = "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.";
export const DEFAULT_HEARTBEAT_EVERY = "30m";
export const DEFAULT_HEARTBEAT_ACK_MAX_CHARS = 300;
const lines = content.split("\n"); for (const line of lines) { const trimmed = line.trim(); // Skip empty lines if (!trimmed) { continue;
} // Skip markdown header lines (# followed by space or EOL, ## etc) // This intentionally does NOT skip lines like "#TODO" or "#hashtag" which might be content // (Those aren't valid markdown headers - ATX headers require space after #) if (/^#+(\s|$)/.test(trimmed)) { continue;
} // Skip empty markdown list items like "- [ ]" or "* [ ]" or just "- " if (/^[-*+]\s*(\[[\sXx]?\]\s*)?$/.test(trimmed)) { continue;
} // Ignore markdown fence markers that were added for doc rendering but do // not carry task semantics in the workspace template body. if (/^```[A-Za-z0-9_-]*$/.test(trimmed)) { continue;
} // Found a non-empty, non-comment line - there's actionable content returnfalse;
} // All lines were either empty or comments returntrue;
}
let didStrip = false;
let changed = true; while (changed) {
changed = false; const next = text.trim(); if (next.startsWith(token)) { const after = next.slice(token.length).trimStart();
text = after;
didStrip = true;
changed = true; continue;
} // Strip the token when it appears at the end of the text. // Also strip up to 4 trailing non-word characters the model may have appended // (e.g. ".", "!!!", "---"). Keep trailing punctuation only when real // sentence text exists before the token. if (tokenAtEndWithOptionalTrailingPunctuation.test(next)) { const idx = next.lastIndexOf(token); const before = next.slice(0, idx).trimEnd(); if (!before) {
text = "";
} else { const after = next.slice(idx + token.length).trimStart();
text = `${before}${after}`.trimEnd();
}
didStrip = true;
changed = true;
}
}
// Normalize lightweight markup so HEARTBEAT_OK wrapped in HTML/Markdown // (e.g., <b>HEARTBEAT_OK</b> or **HEARTBEAT_OK**) still strips. const stripMarkup = (text: string) =>
text // Drop HTML tags.
.replace(/<[^>]*>/g, " ") // Decode common nbsp variant.
.replace(/ /gi, " ") // Remove markdown-ish wrappers at the edges.
.replace(/^[*`~_]+/, "")
.replace(/[*`~_]+$/, "");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.