fix(cron): preserve parent session updatedAt for isolated cron jobs#51026
fix(cron): preserve parent session updatedAt for isolated cron jobs#51026QuinnH496 wants to merge 1 commit into
Conversation
Greptile SummaryThis PR addresses two separate concerns: (1) the primary fix prevents isolated cron jobs whose Key changes:
One minor gap noted: Confidence Score: 4/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/usage.ts
Line: 93-102
Comment:
**Missing `cached_tokens` in nested usage check**
`hasNonzeroUsage` checks `usageObj.prompt_tokens`, `usageObj.completion_tokens`, and `usageObj.total_tokens` from the nested object, but omits `usageObj.cached_tokens`. This creates an inconsistency with `normalizeUsage`, which correctly maps `usageObj.cached_tokens` → `cacheRead`.
In the unlikely but possible case where a Bailian API response returns non-zero `cached_tokens` with zero prompt/completion/total tokens, `hasNonzeroUsage` would return `false` while `normalizeUsage` would return a non-undefined result with a non-zero `cacheRead`. Callers that guard behind `hasNonzeroUsage` (e.g. `pi-embedded-subscribe.ts:274`) would silently discard that usage.
```suggestion
return [
usage.input,
usage.output,
usage.cacheRead,
usage.cacheWrite,
usage.total,
usageObj.prompt_tokens,
usageObj.completion_tokens,
usageObj.total_tokens,
usageObj.cached_tokens,
].some(
```
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "fix(cron): preserve ..." |
| return [ | ||
| usage.input, | ||
| usage.output, | ||
| usage.cacheRead, | ||
| usage.cacheWrite, | ||
| usage.total, | ||
| usageObj.prompt_tokens, | ||
| usageObj.completion_tokens, | ||
| usageObj.total_tokens, | ||
| ].some( |
There was a problem hiding this comment.
Missing
cached_tokens in nested usage check
hasNonzeroUsage checks usageObj.prompt_tokens, usageObj.completion_tokens, and usageObj.total_tokens from the nested object, but omits usageObj.cached_tokens. This creates an inconsistency with normalizeUsage, which correctly maps usageObj.cached_tokens → cacheRead.
In the unlikely but possible case where a Bailian API response returns non-zero cached_tokens with zero prompt/completion/total tokens, hasNonzeroUsage would return false while normalizeUsage would return a non-undefined result with a non-zero cacheRead. Callers that guard behind hasNonzeroUsage (e.g. pi-embedded-subscribe.ts:274) would silently discard that usage.
| return [ | |
| usage.input, | |
| usage.output, | |
| usage.cacheRead, | |
| usage.cacheWrite, | |
| usage.total, | |
| usageObj.prompt_tokens, | |
| usageObj.completion_tokens, | |
| usageObj.total_tokens, | |
| ].some( | |
| return [ | |
| usage.input, | |
| usage.output, | |
| usage.cacheRead, | |
| usage.cacheWrite, | |
| usage.total, | |
| usageObj.prompt_tokens, | |
| usageObj.completion_tokens, | |
| usageObj.total_tokens, | |
| usageObj.cached_tokens, | |
| ].some( |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/usage.ts
Line: 93-102
Comment:
**Missing `cached_tokens` in nested usage check**
`hasNonzeroUsage` checks `usageObj.prompt_tokens`, `usageObj.completion_tokens`, and `usageObj.total_tokens` from the nested object, but omits `usageObj.cached_tokens`. This creates an inconsistency with `normalizeUsage`, which correctly maps `usageObj.cached_tokens` → `cacheRead`.
In the unlikely but possible case where a Bailian API response returns non-zero `cached_tokens` with zero prompt/completion/total tokens, `hasNonzeroUsage` would return `false` while `normalizeUsage` would return a non-undefined result with a non-zero `cacheRead`. Callers that guard behind `hasNonzeroUsage` (e.g. `pi-embedded-subscribe.ts:274`) would silently discard that usage.
```suggestion
return [
usage.input,
usage.output,
usage.cacheRead,
usage.cacheWrite,
usage.total,
usageObj.prompt_tokens,
usageObj.completion_tokens,
usageObj.total_tokens,
usageObj.cached_tokens,
].some(
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d14258b5e2
ℹ️ 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".
| cronSession.store[agentSessionKey] = mergeSessionEntryPreserveActivity( | ||
| cronSession.store[agentSessionKey], | ||
| cronSession.sessionEntry, |
There was a problem hiding this comment.
Preserve activity only when writing parent session key
persistSessionEntry now always uses mergeSessionEntryPreserveActivity for agentSessionKey, which freezes updatedAt for normal cron-owned sessions too. On subsequent runs, resolveCronSession evaluates freshness from that stale timestamp, so after the daily/idle boundary it will treat an actively running cron session as stale and rotate to a new session unnecessarily. This breaks shared cron context continuity for jobs that are not targeting a parent user session key.
Useful? React with 👍 / 👎.
| const usageObj = (usage as any).usage ?? usage; | ||
| return [ |
There was a problem hiding this comment.
Normalize nested usage before narrowing to NormalizedUsage
hasNonzeroUsage now returns true for nested usage.prompt_tokens-style payloads, but the function still narrows the argument to NormalizedUsage. Callers that rely on that guard then read usage.input/output/cache* and can persist zeros when the payload is nested-only, so usage/cost accounting becomes incorrect even though nonzero usage was detected. The guard should either normalize first or avoid claiming the value is already NormalizedUsage in this branch.
Useful? React with 👍 / 👎.
Isolated cron jobs with sessionKey matching the main session key were overwriting the parent session's updatedAt, preventing daily session reset from triggering. This fix uses mergeSessionEntryPreserveActivity to preserve the parent session's activity timestamp when writing to the agent session key. Fixes #51000
d14258b to
2e9746a
Compare
|
Thanks for documenting the isolated-cron What changed in the replacement:
This PR’s root diagnosis was correct, but the replacement removes |
Problem
Isolated cron jobs with
sessionKeymatching the main session key were overwriting the parent session'supdatedAt, preventing daily session reset from triggering. This caused users to get previous day's session with stale context instead of a fresh start.Solution
Use
mergeSessionEntryPreserveActivitywhen writing to the agent session key to preserve the parent session's activity timestamp. This prevents isolated cron jobs from bumping theupdatedAtpast the daily reset boundary.Changes
mergeSessionEntryPreserveActivityfrom sessions modulepersistSessionEntryto merge entries preserving activityTesting
Manual testing needed: Configure an isolated cron job with
sessionKey: "agent:main:main"that runs after the daily reset hour, then verify that the daily reset still triggers correctly.Fixes #51000