feat: add agent API and operational analytics

This commit is contained in:
jjbrunton committed 2026-08-08 22:08:14 +01:00
1 parent 720ea0652a
commit e8b730b592
65 files changed
+2650 -1214

No files matched your search

+20 -3
View File
@@ -17,6 +17,7 @@ function createMockRedditApi(posts: RedditPost[] = []): RedditApiClient {
function createMockPostsRepo(processedIds: Set<string> = new Set()): PostsRepository {
return {
isProcessed: vi.fn((id: string) => processedIds.has(id)),
isProcessedAnywhere: vi.fn((id: string) => processedIds.has(id)),
insert: vi.fn(),
updateAnalysis: vi.fn(),
markMessageSent: vi.fn(),
@@ -86,6 +87,23 @@ describe('MonitorService', () => {
expect(result.length).toBe(0);
});
it('uses shared post history so another account cannot rediscover a post', async () => {
const post: RedditPost = {
id: 't3_shared', subreddit: 'sub1', author: 'user1', title: 'Post',
url: 'http://example.com/1.jpg', permalink: '/r/sub1/1', thumbnail: '',
is_self: false, created_utc: Date.now() / 1000, over_18: false, spoiler: false,
};
const redditApi = createMockRedditApi([post]);
const postsRepo = createMockPostsRepo();
vi.mocked(postsRepo.isProcessed).mockReturnValue(false);
vi.mocked(postsRepo.isProcessedAnywhere).mockReturnValue(true);
const config = getTestConfig({ reddit: { subreddits: [{ name: 'sub1', type: 'image' }] } });
monitor = new MonitorService(redditApi, postsRepo, createMockMessagesRepo(), config, logger, 0);
await expect(monitor.getUnprocessedPosts()).resolves.toEqual([]);
expect(postsRepo.isProcessedAnywhere).toHaveBeenCalledWith(post.id);
});
it('skips posts from users already messaged', async () => {
const post1: RedditPost = {
id: 't3_1', subreddit: 'sub1', author: 'already_msgd', title: 'Post 1',
@@ -370,7 +388,7 @@ describe('MonitorService', () => {
// (We can't directly test the shuffle, but we can verify it doesn't crash)
});
it('limits results to 10 per author via postsRepo', async () => {
it('checks shared processed-post history before considering a candidate', async () => {
const post: RedditPost = {
id: 't3_1', subreddit: 'sub1', author: 'user1', title: 'Post',
url: 'http://example.com/1.jpg', permalink: '/r/sub1/1', thumbnail: '',
@@ -385,8 +403,7 @@ describe('MonitorService', () => {
monitor = new MonitorService(redditApi, postsRepo, messagesRepo, config, logger, 0);
await monitor.getUnprocessedPosts();
// Verify isProcessed was called
expect(postsRepo.isProcessed).toHaveBeenCalledWith('t3_1');
expect(postsRepo.isProcessedAnywhere).toHaveBeenCalledWith('t3_1');
});
describe('image/chat interleaving', () => {