feat: add seq cursor, work_items, provider fallback, and delivery reliability

Major reliability improvements to the message processing pipeline:

- Add messages.seq monotonic cursor replacing timestamp-based cursors,
  preventing message loss from timestamp collisions with LIMIT queries
- Add work_items table separating agent production from delivery,
  enabling delivery retry without re-running the agent
- Propagate Discord send failures instead of silently swallowing them
- Add Claude 429 → Kimi K2.5 automatic provider fallback with cooldown
- Fix follow-up turn state reset in live index.ts path (not just
  message-runtime.ts) to prevent final output from being lost
- Add restart context tracking for graceful restart announcements
- Lazy migration from timestamp cursors to seq cursors for existing data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eyejoker
2026-03-23 00:11:32 +09:00
parent dd15585941
commit b647502a10
19 changed files with 2782 additions and 209 deletions

View File

@@ -61,6 +61,7 @@ describe('task scheduler', () => {
id: 'task-claude',
group_folder: 'shared-group',
chat_jid: 'shared@g.us',
agent_type: 'claude-code',
prompt: 'claude task',
schedule_type: 'once',
schedule_value: dueAt,
@@ -126,7 +127,11 @@ Check the run.
expect(extractWatchCiTarget(prompt)).toBe('GitHub Actions run 123456');
const rendered = renderWatchCiStatusMessage({
task: { prompt },
task: {
prompt,
schedule_type: 'interval',
schedule_value: '60000',
} as any,
phase: 'waiting',
checkedAt: '2026-03-19T07:02:10.000Z',
nextRun: '2026-03-19T07:04:10.000Z',
@@ -134,9 +139,11 @@ Check the run.
expect(rendered).toContain('CI 감시 중: GitHub Actions run 123456');
expect(rendered).toContain('- 상태: 대기 중');
expect(rendered).toContain('- 마지막 확인:');
expect(rendered).toContain('- 다음 확인:');
expect(rendered).not.toContain('2분 10초');
expect(rendered).toContain('- 마지막 확인: 16시 02분 10초');
expect(rendered).toContain('- 확인 간격: 1분');
expect(rendered).toContain('- 다음 확인: 16시 04분 10초');
expect(rendered).not.toContain('16:02:10');
expect(rendered).not.toContain('16:04:10');
});
it('computeNextRun anchors interval tasks to scheduled time to prevent drift', () => {