Skip to content

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

Merged
steipete merged 3 commits intoopenclaw:mainfrom
scoootscooob:fix/reminder-note-suppress-active-cron
Mar 2, 2026
Merged

fix(reply): suppress unscheduled-reminder note when session has active cron#32255
steipete merged 3 commits intoopenclaw:mainfrom
scoootscooob:fix/reminder-note-suppress-active-cron

Conversation

@scoootscooob
Copy link
Contributor

Summary

  • Before appending the "I did not schedule a reminder" guard note, checks the cron store for enabled jobs matching the current session key
  • 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)
  • Session-scoped check: only suppresses when the same session has an enabled cron, so unrelated cron jobs don't suppress the note
  • The cron store read only fires on the rare path where the text matches commitment patterns AND no cron was added in the current turn — negligible I/O impact

Test plan

  • Existing tests pass (26 tests in agent-runner.misc.runreplyagent.test.ts)
  • New test: guard note suppressed when session has active cron job
  • New test: guard note still shown when cron jobs exist for a different session
  • New test: guard note still shown when session cron jobs are disabled
  • Full reply test suite passes (573 tests across 45 files)

Closes #32228

🤖 Generated with Claude Code

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f1aba7d838

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// 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);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep reminder guard unless a matching cron is verified

This suppression check treats any enabled cron in the same session as proof that the new reminder commitment is covered. If a session already has an unrelated job (for example, a daily digest cron), a reply like “I’ll remind you tomorrow” with successfulCronAdds === 0 will no longer get the safety note, so users can be told a reminder will happen when no new reminder was actually scheduled.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

This PR adds a session-scoped cron store check before appending the "I did not schedule a reminder" guard note, suppressing it when an existing enabled cron job from the same session already covers the commitment. The approach is sound and the three new tests cover the key scenarios well. One logic issue exists: the fallback branch in hasSessionRelatedCronJobs — reached when sessionKey is undefined — returns true for any enabled job in the entire store, which can suppress the note due to a cron job from a completely unrelated session, contradicting the PR's stated session-scoping goal.

  • agent-runner.ts: introduces hasSessionRelatedCronJobs; the session-scoped path is correct but the undefined-sessionKey fallback is overly broad
  • agent-runner.misc.runreplyagent.test.ts: clean mock setup with a safe default and three well-targeted new tests

Confidence Score: 3/5

  • Safe to merge with a minor fix — the logic works correctly for the common case but has an over-broad fallback when sessionKey is absent.
  • The core session-scoped check is correct and all new + existing tests pass. The concern is the fallback branch that fires when sessionKey is undefined: it returns true for any enabled cron job in the store (cross-session), silently suppressing the guard note in an edge case the PR explicitly says it wants to avoid. This is a real logic defect, though it is unlikely to be hit in typical deployments where sessionKey is always provided.
  • Focus on src/auto-reply/reply/agent-runner.ts lines 92–96 — the fallback branch in hasSessionRelatedCronJobs.

Last reviewed commit: f1aba7d

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +92 to +96
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fallback suppresses note across unrelated sessions

When params.sessionKey is undefined, the fallback at line 96 returns true for any enabled cron job in the store — including jobs belonging to completely different sessions. This directly contradicts the PR's stated goal of session-scoped suppression and could produce exactly the cross-session false positive the PR is trying to prevent.

Since sessionKey is declared as sessionKey?: string on the runReplyAgent params (line 134 in the function signature), it genuinely can be undefined at runtime. A caller that omits sessionKey while another session holds an active cron job would have its reminder guard note silently suppressed.

The safest fix is to return false (don't suppress) when no session key is available rather than broadening to all enabled jobs:

Suggested change
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);
if (params.sessionKey) {
return store.jobs.some((job) => job.enabled && job.sessionKey === params.sessionKey);
}
// No session key available — cannot scope the check, so do not suppress the note.
return false;
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/reply/agent-runner.ts
Line: 92-96

Comment:
**Fallback suppresses note across unrelated sessions**

When `params.sessionKey` is `undefined`, the fallback at line 96 returns `true` for any enabled cron job in the store — including jobs belonging to completely different sessions. This directly contradicts the PR's stated goal of session-scoped suppression and could produce exactly the cross-session false positive the PR is trying to prevent.

Since `sessionKey` is declared as `sessionKey?: string` on the `runReplyAgent` params (line 134 in the function signature), it genuinely can be `undefined` at runtime. A caller that omits `sessionKey` while another session holds an active cron job would have its reminder guard note silently suppressed.

The safest fix is to return `false` (don't suppress) when no session key is available rather than broadening to all enabled jobs:

```suggestion
    if (params.sessionKey) {
      return store.jobs.some((job) => job.enabled && job.sessionKey === params.sessionKey);
    }
    // No session key available — cannot scope the check, so do not suppress the note.
    return false;
```

How can I resolve this? If you propose a fix, please make it concise.

scoootscooob and others added 3 commits March 2, 2026 23:33
…as 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 openclaw#32228

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address Greptile review: when sessionKey is undefined the fallback
matched any enabled cron job, which could silently suppress the guard
note due to jobs from unrelated sessions.  Return false instead so the
note always appears when session scoping is not possible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@steipete steipete force-pushed the fix/reminder-note-suppress-active-cron branch from 9a7c813 to ebb9fbf Compare March 2, 2026 23:35
@steipete steipete merged commit 73e08ed into openclaw:main Mar 2, 2026
9 checks passed
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Landed via temp rebase onto main.

  • Gate: pnpm -s vitest run src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts && pnpm -s tsgo
  • Land commit: ebb9fbf
  • Merge commit: 73e08ed

Thanks @scoootscooob!

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebb9fbf019

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 577 to +580
hasReminderCommitment && successfulCronAdds === 0
? await hasSessionRelatedCronJobs({
cronStorePath: cfg.cron?.store,
sessionKey,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve reminder guard when cron is globally disabled

This suppression path only checks for an enabled job in the store, so it will hide the unscheduled-reminder warning even when cron.enabled is off. In that configuration, CronService.start() exits early (src/cron/service/ops.ts:90-93), so stored jobs will not execute, but coveredByExistingCron can still become true here if a same-session job remains marked enabled in jobs.json. The result is a user-facing promise like “I’ll remind you…” without either scheduling a new reminder or showing the safety note.

Useful? React with 👍 / 👎.

dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
OWALabuy pushed a commit to kcinzgg/openclaw that referenced this pull request Mar 4, 2026
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unscheduled reminder note triggers even when relevant cron already exists

2 participants