A chill Bluesky bot, with responses powered by Gemini.
1import { and, desc, eq } from "drizzle-orm";
2import db from "../db";
3import { memory_block_entries, memory_blocks } from "../db/schema";
4import * as yaml from "js-yaml";
5
6type MemoryBlock = {
7 id: number;
8 name: string;
9 description: string;
10 mutable: boolean;
11 entries: Entry[];
12};
13
14type Entry = {
15 id: number;
16 block_id: number;
17 label: string;
18 value: string;
19 added_by: string | null;
20 created_at: Date | null;
21};
22
23export class MemoryHandler {
24 did: string;
25 blocks: MemoryBlockHandler[];
26
27 constructor(did: string, blocks: MemoryBlockHandler[]) {
28 this.did = did;
29 this.blocks = blocks;
30 }
31
32 static async getBlocks(did: string) {
33 const blocks = await db
34 .select({
35 id: memory_blocks.id,
36 name: memory_blocks.name,
37 description: memory_blocks.description,
38 mutable: memory_blocks.mutable,
39 })
40 .from(memory_blocks)
41 .where(eq(memory_blocks.did, did));
42
43 const hydratedBlocks = [];
44
45 for (const block of blocks) {
46 const entries = await db
47 .select()
48 .from(memory_block_entries)
49 .where(eq(memory_block_entries.block_id, block.id))
50 .orderBy(desc(memory_block_entries.id))
51 .limit(15);
52
53 hydratedBlocks.push({
54 ...block,
55 entries,
56 });
57 }
58
59 if (hydratedBlocks.length == 0) {
60 const [newBlock] = await db
61 .insert(memory_blocks)
62 .values([
63 {
64 did,
65 name: "memory",
66 description: "User memory",
67 mutable: false,
68 },
69 ])
70 .returning();
71
72 hydratedBlocks.push({
73 ...newBlock,
74 entries: [],
75 });
76 }
77
78 return hydratedBlocks.map(
79 (block) =>
80 new MemoryBlockHandler(
81 block as MemoryBlock,
82 ),
83 );
84 }
85
86 public parseBlocks() {
87 return this.blocks.map((handler) => ({
88 name: handler.block.name,
89 description: handler.block.description,
90 entries: handler.block.entries.map((entry) => ({
91 label: entry.label,
92 value: entry.value,
93 added_by: entry.added_by || "nobody",
94 })),
95 }));
96 }
97}
98
99export class MemoryBlockHandler {
100 block: MemoryBlock;
101
102 constructor(block: MemoryBlock) {
103 this.block = block;
104 }
105
106 public async createEntry(label: string, value: string) {
107 const [entry] = await db
108 .insert(memory_block_entries)
109 .values([
110 {
111 block_id: this.block.id,
112 label,
113 value,
114 },
115 ])
116 .returning();
117
118 if (!entry) {
119 return {
120 added_to_memory: false,
121 };
122 }
123
124 this.block.entries.push(entry);
125
126 return {
127 added_to_memory: true,
128 };
129 }
130}