(agent: Agent, opts: CronManagerOptions = {})
| 141 | private readonly persistQueues: Map<string, Promise<void>> = new Map(); |
| 142 | |
| 143 | constructor(agent: Agent, opts: CronManagerOptions = {}) { |
| 144 | this.agent = agent; |
| 145 | this.store = new SessionCronStore(); |
| 146 | this.clocks = |
| 147 | opts.clocks ?? |
| 148 | resolveClockSources(process.env['KIMI_CRON_CLOCK']) ?? |
| 149 | SYSTEM_CLOCKS; |
| 150 | this.persistStore = |
| 151 | agent.homedir === undefined |
| 152 | ? undefined |
| 153 | : createCronPersistStore(agent.homedir); |
| 154 | |
| 155 | this.scheduler = createCronScheduler({ |
| 156 | clocks: this.clocks, |
| 157 | source: () => this.store.list(), |
| 158 | isIdle: () => !agent.turn.hasActiveTurn, |
| 159 | isKilled: () => process.env['KIMI_DISABLE_CRON'] === '1', |
| 160 | onFire: (task, ctx) => { |
| 161 | this.handleFire(task, ctx); |
| 162 | }, |
| 163 | removeOneShot: (id) => { |
| 164 | this.removeTasks([id]); |
| 165 | }, |
| 166 | onAdvanceCursor: (id, lastFiredAt) => { |
| 167 | this.advanceCursor(id, lastFiredAt); |
| 168 | }, |
| 169 | // P1.8: `KIMI_CRON_MANUAL_TICK=1` forces the scheduler into |
| 170 | // manual-drive mode (no setInterval), so bench / time-injected |
| 171 | // tests can step time forward and call `tick()` explicitly without |
| 172 | // racing a 1-second auto-tick. Explicit caller overrides |
| 173 | // (`opts.pollIntervalMs`) lose to the env so a bench can flip the |
| 174 | // switch from the outside without rebuilding the manager wiring. |
| 175 | pollIntervalMs: |
| 176 | process.env['KIMI_CRON_MANUAL_TICK'] === '1' |
| 177 | ? null |
| 178 | : opts.pollIntervalMs, |
| 179 | }); |
| 180 | |
| 181 | this.start(); |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * Add a fresh task to the in-memory store and, when persistence is |
nothing calls this directly
no test coverage detected