fix: prevent full message history from being sent to container agents
When lastAgentTimestamp was missing (new group, corrupted state, or startup recovery), the empty-string fallback caused getMessagesSince to return up to 200 messages — the entire group history. This sent a massive prompt to the container agent instead of just recent messages. Fix: recover the cursor from the last bot reply timestamp in the DB (proof of what we already processed), and cap all prompt queries to a configurable MAX_MESSAGES_PER_PROMPT (default 10). Covers all three call sites: processGroupMessages, the piping path, and recoverPendingMessages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
src/index.ts
38
src/index.ts
@@ -9,6 +9,7 @@ import {
|
||||
getTriggerPattern,
|
||||
GROUPS_DIR,
|
||||
IDLE_TIMEOUT,
|
||||
MAX_MESSAGES_PER_PROMPT,
|
||||
ONECLI_URL,
|
||||
POLL_INTERVAL,
|
||||
TIMEZONE,
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
getAllRegisteredGroups,
|
||||
getAllSessions,
|
||||
getAllTasks,
|
||||
getLastBotMessageTimestamp,
|
||||
getMessagesSince,
|
||||
getNewMessages,
|
||||
getRouterState,
|
||||
@@ -112,6 +114,27 @@ function loadState(): void {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message cursor for a group, recovering from the last bot reply
|
||||
* if lastAgentTimestamp is missing (new group, corrupted state, restart).
|
||||
*/
|
||||
function getOrRecoverCursor(chatJid: string): string {
|
||||
const existing = lastAgentTimestamp[chatJid];
|
||||
if (existing) return existing;
|
||||
|
||||
const botTs = getLastBotMessageTimestamp(chatJid, ASSISTANT_NAME);
|
||||
if (botTs) {
|
||||
logger.info(
|
||||
{ chatJid, recoveredFrom: botTs },
|
||||
'Recovered message cursor from last bot reply',
|
||||
);
|
||||
lastAgentTimestamp[chatJid] = botTs;
|
||||
saveState();
|
||||
return botTs;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function saveState(): void {
|
||||
setRouterState('last_timestamp', lastTimestamp);
|
||||
setRouterState('last_agent_timestamp', JSON.stringify(lastAgentTimestamp));
|
||||
@@ -205,11 +228,11 @@ async function processGroupMessages(chatJid: string): Promise<boolean> {
|
||||
|
||||
const isMainGroup = group.isMain === true;
|
||||
|
||||
const sinceTimestamp = lastAgentTimestamp[chatJid] || '';
|
||||
const missedMessages = getMessagesSince(
|
||||
chatJid,
|
||||
sinceTimestamp,
|
||||
getOrRecoverCursor(chatJid),
|
||||
ASSISTANT_NAME,
|
||||
MAX_MESSAGES_PER_PROMPT,
|
||||
);
|
||||
|
||||
if (missedMessages.length === 0) return true;
|
||||
@@ -460,8 +483,9 @@ async function startMessageLoop(): Promise<void> {
|
||||
// context that accumulated between triggers is included.
|
||||
const allPending = getMessagesSince(
|
||||
chatJid,
|
||||
lastAgentTimestamp[chatJid] || '',
|
||||
getOrRecoverCursor(chatJid),
|
||||
ASSISTANT_NAME,
|
||||
MAX_MESSAGES_PER_PROMPT,
|
||||
);
|
||||
const messagesToSend =
|
||||
allPending.length > 0 ? allPending : groupMessages;
|
||||
@@ -500,8 +524,12 @@ async function startMessageLoop(): Promise<void> {
|
||||
*/
|
||||
function recoverPendingMessages(): void {
|
||||
for (const [chatJid, group] of Object.entries(registeredGroups)) {
|
||||
const sinceTimestamp = lastAgentTimestamp[chatJid] || '';
|
||||
const pending = getMessagesSince(chatJid, sinceTimestamp, ASSISTANT_NAME);
|
||||
const pending = getMessagesSince(
|
||||
chatJid,
|
||||
getOrRecoverCursor(chatJid),
|
||||
ASSISTANT_NAME,
|
||||
MAX_MESSAGES_PER_PROMPT,
|
||||
);
|
||||
if (pending.length > 0) {
|
||||
logger.info(
|
||||
{ group: group.name, pendingCount: pending.length },
|
||||
|
||||
Reference in New Issue
Block a user