feat: use jetstream instead of firehose

This commit is contained in:
Index 2025-11-03 22:11:12 -06:00
parent f237f33946
commit dda2552126
6 changed files with 58 additions and 12 deletions

View file

@ -11,10 +11,10 @@ DID=""
HANDLE=""
# https://bsky.app/settings/app-passwords
BSKY_PASSWORD=""
APP_PASSWORD=""
# https://aistudio.google.com/apikey
GEMINI_API_KEY=""
DAILY_QUERY_LIMIT=15
USE_FIREHOSE=false
USE_JETSTREAM=false

View file

@ -10,7 +10,7 @@ services:
- "GEMINI_MODEL=${GEMINI_MODEL:-gemini-2.5-flash}"
- "DID=${DID:?}"
- "HANDLE=${HANDLE:?}"
- "BSKY_PASSWORD=${BSKY_PASSWORD:?}"
- "APP_PASSWORD=${APP_PASSWORD:?}"
- "GEMINI_API_KEY=${GEMINI_API_KEY:?}"
volumes:
- aero_db:/sqlite.db

View file

@ -1,13 +1,57 @@
import { GoogleGenAI } from "@google/genai";
import { Bot, EventStrategy } from "@skyware/bot";
import { env } from "./env";
import type { BinaryType } from "bun";
// Websocket patch was written by Claude, hopefully it doesn't suck
const OriginalWebSocket = global.WebSocket;
const binaryTypeDescriptor = Object.getOwnPropertyDescriptor(
OriginalWebSocket.prototype,
"binaryType",
);
const originalSetter = binaryTypeDescriptor?.set;
if (OriginalWebSocket && originalSetter) {
global.WebSocket = new Proxy(OriginalWebSocket, {
construct(target, args) {
//@ts-ignore
const ws = new target(...args) as WebSocket & {
_binaryType?: BinaryType;
};
Object.defineProperty(ws, "binaryType", {
get(): BinaryType {
return ws._binaryType ||
(binaryTypeDescriptor.get
? binaryTypeDescriptor.get.call(ws)
: "arraybuffer");
},
set(value: BinaryType) {
//@ts-ignore
if (value === "blob") {
originalSetter.call(ws, "arraybuffer");
//@ts-ignore
ws._binaryType = "blob";
} else {
originalSetter.call(ws, value);
ws._binaryType = value;
}
},
configurable: true,
});
return ws;
},
}) as typeof WebSocket;
}
export const bot = new Bot({
service: env.SERVICE,
emitChatEvents: true,
eventEmitterOptions: {
strategy: env.USE_FIREHOSE
? EventStrategy.Firehose
strategy: env.USE_JETSTREAM
? EventStrategy.Jetstream
: EventStrategy.Polling,
},
});

View file

@ -11,9 +11,11 @@ const envSchema = z.object({
DB_PATH: z.string().default("sqlite.db"),
GEMINI_MODEL: z.string().default("gemini-2.5-flash"),
ADMIN_DID: z.string().optional(),
DID: z.string(),
HANDLE: z.string(),
BSKY_PASSWORD: z.string(),
APP_PASSWORD: z.string(),
GEMINI_API_KEY: z.string(),
DAILY_QUERY_LIMIT: z.preprocess(
@ -21,7 +23,7 @@ const envSchema = z.object({
(typeof val === "string" && val.trim() !== "") ? Number(val) : undefined,
z.number().int().positive().default(15),
),
USE_FIREHOSE: z.preprocess(
USE_JETSTREAM: z.preprocess(
(val) => val === "true",
z.boolean().default(false),
),

View file

@ -170,12 +170,12 @@ export async function handler(message: ChatMessage): Promise<void> {
throw new Error("Failed to generate text. Returned undefined.");
}
logger.success("Generated text:", inference.text);
saveMessage(conversation, env.DID, inference.text!);
const responseText = inference.text;
if (responseText) {
logger.success("Generated text:", inference.text);
saveMessage(conversation, env.DID, inference.text!);
await sendResponse(conversation, responseText);
}
} catch (error) {

View file

@ -11,7 +11,7 @@ logger.info("Logging in..");
try {
await bot.login({
identifier: env.HANDLE,
password: env.BSKY_PASSWORD,
password: env.APP_PASSWORD,
});
logger.success(`Logged in as @${env.HANDLE} (${env.DID})`);