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

@@ -761,7 +761,7 @@ describe('DiscordChannel', () => {
expect(currentClient().channels.fetch).toHaveBeenCalledWith('9876543210');
});
it('handles send failure gracefully', async () => {
it('propagates send failure to the caller', async () => {
const opts = createTestOpts();
const channel = new DiscordChannel('test-token', opts);
await channel.connect();
@@ -770,10 +770,9 @@ describe('DiscordChannel', () => {
new Error('Channel not found'),
);
// Should not throw
await expect(
channel.sendMessage('dc:1234567890123456', 'Will fail'),
).resolves.toBeUndefined();
).rejects.toThrow('Channel not found');
});
it('does nothing when client is not initialized', async () => {