fix(reply): suppress unscheduled-reminder note when session already has active cron

Before appending the "I did not schedule a reminder" guard note, check the
cron store for enabled jobs matching the current session key.  This prevents
false positives when the agent references an existing cron created in a
prior turn (e.g. "I'll ping you when it's done" while a monitoring cron is
already running).

The check only fires on the rare path where the text matches commitment
patterns AND no cron was added in the current turn, so the added I/O is
negligible.

Closes #32228

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
scoootscooob
2026-03-02 14:39:03 -08:00
committed by Peter Steinberger
parent 55f04636f3
commit abb0252a1a
2 changed files with 132 additions and 1 deletions

View File

@@ -15,6 +15,7 @@ import {
updateSessionStoreEntry,
} from "../../config/sessions.js";
import type { TypingMode } from "../../config/types.js";
import { loadCronStore, resolveCronStorePath } from "../../cron/store.js";
import { emitAgentEvent } from "../../infra/agent-events.js";
import { emitDiagnosticEvent, isDiagnosticsEnabled } from "../../infra/diagnostic-events.js";
import { generateSecureUuid } from "../../infra/secure-random.js";
@@ -71,6 +72,34 @@ function hasUnbackedReminderCommitment(text: string): boolean {
return REMINDER_COMMITMENT_PATTERNS.some((pattern) => pattern.test(text));
}
/**
* Returns true when the cron store has at least one enabled job that shares the
* current session key. Used to suppress the "no reminder scheduled" guard note
* when an existing cron (created in a prior turn) already covers the commitment.
*/
async function hasSessionRelatedCronJobs(params: {
cronStorePath?: string;
sessionKey?: string;
}): Promise<boolean> {
try {
const storePath = resolveCronStorePath(params.cronStorePath);
const store = await loadCronStore(storePath);
if (store.jobs.length === 0) {
return false;
}
// If we have a session key, only consider cron jobs from the same session.
// This avoids suppressing the note due to unrelated cron jobs.
if (params.sessionKey) {
return store.jobs.some((job) => job.enabled && job.sessionKey === params.sessionKey);
}
// Fallback: any enabled cron job counts.
return store.jobs.some((job) => job.enabled);
} catch {
// If we cannot read the cron store, do not suppress the note.
return false;
}
}
function appendUnscheduledReminderNote(payloads: ReplyPayload[]): ReplyPayload[] {
let appended = false;
return payloads.map((payload) => {
@@ -540,8 +569,17 @@ export async function runReplyAgent(params: {
typeof payload.text === "string" &&
hasUnbackedReminderCommitment(payload.text),
);
const guardedReplyPayloads =
// Suppress the guard note when an existing cron job (created in a prior
// turn) already covers the commitment — avoids false positives (#32228).
const coveredByExistingCron =
hasReminderCommitment && successfulCronAdds === 0
? await hasSessionRelatedCronJobs({
cronStorePath: cfg.cron?.store,
sessionKey,
})
: false;
const guardedReplyPayloads =
hasReminderCommitment && successfulCronAdds === 0 && !coveredByExistingCron
? appendUnscheduledReminderNote(replyPayloads)
: replyPayloads;