You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Persistent cron rotation starts a new chat, preserving the old one (#167)
Rotation used to reset the SDK context in place: every context epoch piled
into one endless cron:{job_id} chat, and since the chat view only loads the
most recent messages, pre-rotation history was effectively invisible.
Now each persistent job runs in a generation chat (cron:{job_id}:{ts})
tracked via channel_sessions. Rotation retires the current chat untouched
(history, usage, and run-log links preserved; browsable like any session),
cancels its pending wakeups, stamps/retitles it, and mints a fresh chat for
subsequent runs. Legacy stable-id sessions are adopted on first run so
existing installs keep their context.
| `session_mode` | string | no | `isolated` (new session per run), `persistent` (reuse context), or `main` |
87
-
| `context_rotate_hours` | int | no | Hours before persistent context resets (default: 24, 0 = never) |
87
+
| `context_rotate_hours` | int | no | Hours before a persistent job rotates to a fresh chat (default: 24, 0 = never). The old chat is preserved |
88
+
| `context_rotate_at` | string | no | Time of day to rotate (e.g. `"04:00"`, in the configured timezone). Overrides the hours-based rotation |
88
89
| `reminder_mode` | bool | no | Persistent only: send short reminder instead of full prompt on subsequent runs (default: false) |
89
90
| `catchup` | bool | no | Fire once on startup if the job missed a run while the server was down (default: true) |
90
91
| `enabled` | bool | no | Whether the job is active (default: true) |
@@ -250,11 +251,16 @@ Each run creates a fresh session (`cron:{job_id}:{timestamp}`). The agent has no
250
251
251
252
### Persistent
252
253
253
-
Jobs with `session_mode: persistent` maintain SDK conversation context across runs:
254
+
Jobs with `session_mode: persistent` maintain SDK conversation context across runs. Each job owns a **generation chat** — one session that is reused run after run until rotation:
254
255
255
-
- **First trigger**: Creates a fresh session (`cron:{job_id}`) and runs the prompt.
256
-
- **Subsequent triggers**: Resumes the same SDK session and sends the prompt as a new message. The agent sees all prior runs in-context.
257
-
- **Context rotation**: Every `context_rotate_hours` (default: 24), the context is reset. Old messages remain in the database and are searchable via memU, but the agent starts with a clean slate.
256
+
- **First trigger**: Creates a fresh generation session (`cron:{job_id}:{timestamp}`) and runs the prompt.
257
+
- **Subsequent triggers**: Resumes the same SDK session and sends the prompt as a new message. The agent sees all prior runs of this generation in-context.
258
+
- **Context rotation**: Every `context_rotate_hours` (default: 24) — or daily at `context_rotate_at` — the current chat is **retired and a brand-new chat is started**. The old chat is preserved exactly as it was: it keeps its full message history, stays browsable (and resumable) in the UI like any other session, and ages out via the normal session archival policy. Retiring also indexes the old context into memU, cancels the old session's pending wakeups (so a retired thread can't resurrect itself alongside the new one), and retitles it with its end date (`Cron: {job_id} (until 2026-07-05)`).
259
+
260
+
> **Upgrade note.** Installs that predate generation chats used the stable id
261
+
> `cron:{job_id}`. That session is adopted as the current generation on the
262
+
> first run after upgrading — its SDK context carries over seamlessly — and
263
+
> moves to the generation scheme on its next rotation.
258
264
259
265
This is useful for jobs that benefit from accumulated context:
260
266
- Monitoring jobs that track changes over time
@@ -263,6 +269,10 @@ This is useful for jobs that benefit from accumulated context:
263
269
264
270
Between runs, the SDK client subprocess is freed (no resource leak). On the next trigger, the SDK resumes the session from its stored state.
265
271
272
+
Rotation can also be forced from the Cron page ("Rotate") or via
273
+
`POST /api/cron/jobs/{job_id}/rotate` — same behavior: the current chat is
274
+
preserved and the next run starts in a fresh one.
275
+
266
276
#### Reminder Mode
267
277
268
278
Persistent jobs with `reminder_mode: true` avoid resending the full prompt on every trigger. Instead:
0 commit comments