A simple Bluesky bot to make sense of the noise, with responses powered by Gemini, similar to Grok.
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add daily message quota

Index df5933cb abb6b8b7

+33
+3
src/core.ts
··· 11 11 apiKey: env.GEMINI_API_KEY, 12 12 }); 13 13 14 + export const QUOTA_EXCEEDED_MESSAGE = 15 + "You have exceeded your daily message quota (15). Please wait 24 hours before trying again."; 16 + 14 17 export const UNAUTHORIZED_MESSAGE = 15 18 "I can’t make sense of your noise just yet. You’ll need to be whitelisted before I can help."; 16 19
+4
src/env.ts
··· 16 16 BSKY_PASSWORD: z.string(), 17 17 18 18 GEMINI_API_KEY: z.string(), 19 + DAILY_QUERY_LIMIT: z.preprocess( 20 + (val) => (typeof val === "string" && val.trim() !== "") ? Number(val) : undefined, 21 + z.number().int().positive().default(15), 22 + ), 19 23 }); 20 24 21 25 export type Env = z.infer<typeof envSchema>;
+26
src/handlers/messages.ts
··· 4 4 import * as tools from "../tools"; 5 5 import consola from "consola"; 6 6 import { env } from "../env"; 7 + import db from "../db"; 8 + import { messages } from "../db/schema"; 9 + import { and, count, eq, gte, lt } from "drizzle-orm"; 7 10 import { 8 11 exceedsGraphemes, 9 12 multipartResponse, ··· 126 129 text: c.UNAUTHORIZED_MESSAGE, 127 130 }); 128 131 132 + return; 133 + } 134 + 135 + const today = new Date(); 136 + today.setHours(0, 0, 0, 0); 137 + const tomorrow = new Date(today); 138 + tomorrow.setDate(tomorrow.getDate() + 1); 139 + 140 + const dailyCount = await db 141 + .select({ count: count(messages.id) }) 142 + .from(messages) 143 + .where( 144 + and( 145 + eq(messages.did, message.senderDid), 146 + gte(messages.created_at, today), 147 + lt(messages.created_at, tomorrow), 148 + ), 149 + ); 150 + 151 + if (dailyCount[0]!.count >= env.DAILY_QUERY_LIMIT) { 152 + conversation.sendMessage({ 153 + text: c.QUOTA_EXCEEDED_MESSAGE, 154 + }); 129 155 return; 130 156 } 131 157