A simple Bluesky bot to make sense of the noise, with responses powered by Gemini, similar to Grok.
1import { GoogleGenAI } from "@google/genai";
2import { Bot, EventStrategy } from "@skyware/bot";
3import { env } from "./env";
4import type { BinaryType } from "bun";
5
6// Websocket patch was written by Claude, hopefully it doesn't suck
7const OriginalWebSocket = global.WebSocket;
8const binaryTypeDescriptor = Object.getOwnPropertyDescriptor(
9 OriginalWebSocket.prototype,
10 "binaryType",
11);
12
13const originalSetter = binaryTypeDescriptor?.set;
14
15if (OriginalWebSocket && originalSetter) {
16 global.WebSocket = new Proxy(OriginalWebSocket, {
17 construct(target, args) {
18 //@ts-ignore
19 const ws = new target(...args) as WebSocket & {
20 _binaryType?: BinaryType;
21 };
22
23 Object.defineProperty(ws, "binaryType", {
24 get(): BinaryType {
25 return ws._binaryType ||
26 (binaryTypeDescriptor.get
27 ? binaryTypeDescriptor.get.call(ws)
28 : "arraybuffer");
29 },
30 set(value: BinaryType) {
31 //@ts-ignore
32 if (value === "blob") {
33 originalSetter.call(ws, "arraybuffer");
34 //@ts-ignore
35 ws._binaryType = "blob";
36 } else {
37 originalSetter.call(ws, value);
38 ws._binaryType = value;
39 }
40 },
41 configurable: true,
42 });
43
44 return ws;
45 },
46 }) as typeof WebSocket;
47}
48
49export const bot = new Bot({
50 service: env.SERVICE,
51 emitChatEvents: true,
52 eventEmitterOptions: {
53 strategy: env.USE_JETSTREAM
54 ? EventStrategy.Jetstream
55 : EventStrategy.Polling,
56 },
57});
58
59export const ai = new GoogleGenAI({
60 apiKey: env.GEMINI_API_KEY,
61});
62
63export const QUOTA_EXCEEDED_MESSAGE =
64 "You have exceeded your daily message quota (15). Please wait 24 hours before trying again.";
65
66export const ERROR_MESSAGE =
67 "Sorry, I ran into an issue analyzing that post. Please try again.";
68
69export const UNAUTHORIZED_MESSAGE =
70 "I can’t make sense of your noise just yet. You’ll need to be whitelisted before I can help.";
71
72export const SUPPORTED_FUNCTION_CALLS = [
73 "search_posts",
74] as const;
75
76export const MAX_GRAPHEMES = 1000;
77
78export const MAX_THREAD_DEPTH = 10;