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>
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
|
|
import {
|
|
editFormattedTrackedChannelMessage,
|
|
sendFormattedChannelMessage,
|
|
sendFormattedTrackedChannelMessage,
|
|
} from './index.js';
|
|
import { Channel } from './types.js';
|
|
|
|
function makeChannel(overrides: Partial<Channel> = {}): Channel {
|
|
return {
|
|
name: 'test',
|
|
connect: async () => {},
|
|
sendMessage: async () => {},
|
|
isConnected: () => true,
|
|
ownsJid: (jid: string) => jid === 'dc:test',
|
|
disconnect: async () => {},
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('index scheduler messaging helpers', () => {
|
|
it('sends formatted tracked messages through sendAndTrack', async () => {
|
|
const sendAndTrack = vi.fn(async () => 'msg-123');
|
|
const channel = makeChannel({ sendAndTrack });
|
|
|
|
const messageId = await sendFormattedTrackedChannelMessage(
|
|
[channel],
|
|
'dc:test',
|
|
'<internal>hidden</internal>watching ci',
|
|
);
|
|
|
|
expect(messageId).toBe('msg-123');
|
|
expect(sendAndTrack).toHaveBeenCalledWith('dc:test', 'watching ci');
|
|
});
|
|
|
|
it('edits formatted tracked messages through editMessage', async () => {
|
|
const editMessage = vi.fn(async () => {});
|
|
const channel = makeChannel({ editMessage });
|
|
|
|
await editFormattedTrackedChannelMessage(
|
|
[channel],
|
|
'dc:test',
|
|
'msg-123',
|
|
'<internal>hidden</internal>still watching',
|
|
);
|
|
|
|
expect(editMessage).toHaveBeenCalledWith(
|
|
'dc:test',
|
|
'msg-123',
|
|
'still watching',
|
|
);
|
|
});
|
|
|
|
it('skips empty messages after formatting', async () => {
|
|
const sendMessage = vi.fn(async () => {});
|
|
const sendAndTrack = vi.fn(async () => 'msg-123');
|
|
const editMessage = vi.fn(async () => {});
|
|
const channel = makeChannel({ sendMessage, sendAndTrack, editMessage });
|
|
|
|
const trackedResult = await sendFormattedTrackedChannelMessage(
|
|
[channel],
|
|
'dc:test',
|
|
'<internal>only hidden</internal>',
|
|
);
|
|
await editFormattedTrackedChannelMessage(
|
|
[channel],
|
|
'dc:test',
|
|
'msg-123',
|
|
'<internal>only hidden</internal>',
|
|
);
|
|
await sendFormattedChannelMessage(
|
|
[channel],
|
|
'dc:test',
|
|
'<internal>only hidden</internal>',
|
|
);
|
|
|
|
expect(trackedResult).toBeNull();
|
|
expect(sendAndTrack).not.toHaveBeenCalled();
|
|
expect(editMessage).not.toHaveBeenCalled();
|
|
expect(sendMessage).not.toHaveBeenCalled();
|
|
});
|
|
});
|