I've made some improvements to how I learn from our interactions.
I've updated the way I log our conversations so I can better remember your posts, my responses, and whether a particular conversation is muted. To give you more relevant and personalized responses, I'll also review our last five interactions to get better context for your requests. I'll be sure to exclude messages from our current conversation to avoid repeating myself.
This commit is contained in:
parent
16d51a1d29
commit
f6132057a2
9 changed files with 333 additions and 15 deletions
8
bun.lock
8
bun.lock
|
|
@ -5,20 +5,20 @@
|
|||
"name": "bsky-echo",
|
||||
"dependencies": {
|
||||
"@atproto/syntax": "^0.4.0",
|
||||
"@google/genai": "^1.10.0",
|
||||
"@google/genai": "^1.11.0",
|
||||
"@skyware/bot": "^0.3.12",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"consola": "^3.4.2",
|
||||
"drizzle-orm": "^0.44.3",
|
||||
"drizzle-orm": "^0.44.4",
|
||||
"js-yaml": "^4.1.0",
|
||||
"zod": "^4.0.5",
|
||||
"zod": "^4.0.14",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.2.19",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
"typescript": "^5.8.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
3
drizzle/0003_flowery_korvac.sql
Normal file
3
drizzle/0003_flowery_korvac.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE `interactions` ADD `post` text;--> statement-breakpoint
|
||||
ALTER TABLE `interactions` ADD `response` text;--> statement-breakpoint
|
||||
ALTER TABLE `interactions` ADD `muted` integer;
|
||||
255
drizzle/meta/0003_snapshot.json
Normal file
255
drizzle/meta/0003_snapshot.json
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "30d38111-8e11-4d7d-99e8-cbafd962ca62",
|
||||
"prevId": "11e8b31f-8e38-4013-8d50-bec6177b015a",
|
||||
"tables": {
|
||||
"interactions": {
|
||||
"name": "interactions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"uri": {
|
||||
"name": "uri",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"did": {
|
||||
"name": "did",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"post": {
|
||||
"name": "post",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"response": {
|
||||
"name": "response",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"muted": {
|
||||
"name": "muted",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "CURRENT_TIMESTAMP"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"interactions_uri_unique": {
|
||||
"name": "interactions_uri_unique",
|
||||
"columns": [
|
||||
"uri"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"memory_block_entries": {
|
||||
"name": "memory_block_entries",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"block_id": {
|
||||
"name": "block_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"label": {
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"added_by": {
|
||||
"name": "added_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "CURRENT_TIMESTAMP"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"memory_block_entries_block_id_memory_blocks_id_fk": {
|
||||
"name": "memory_block_entries_block_id_memory_blocks_id_fk",
|
||||
"tableFrom": "memory_block_entries",
|
||||
"tableTo": "memory_blocks",
|
||||
"columnsFrom": [
|
||||
"block_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"memory_blocks": {
|
||||
"name": "memory_blocks",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"did": {
|
||||
"name": "did",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'memory'"
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'User memory'"
|
||||
},
|
||||
"mutable": {
|
||||
"name": "mutable",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"muted_threads": {
|
||||
"name": "muted_threads",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"uri": {
|
||||
"name": "uri",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"rkey": {
|
||||
"name": "rkey",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"muted_at": {
|
||||
"name": "muted_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": "CURRENT_TIMESTAMP"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"muted_threads_uri_unique": {
|
||||
"name": "muted_threads_uri_unique",
|
||||
"columns": [
|
||||
"uri"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"muted_threads_rkey_unique": {
|
||||
"name": "muted_threads_rkey_unique",
|
||||
"columns": [
|
||||
"rkey"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,13 @@
|
|||
"when": 1753682242260,
|
||||
"tag": "0002_green_millenium_guard",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "6",
|
||||
"when": 1754166687687,
|
||||
"tag": "0003_flowery_korvac",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
sqlite.db
Normal file
BIN
sqlite.db
Normal file
Binary file not shown.
|
|
@ -1,6 +1,7 @@
|
|||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||
import { Database } from "bun:sqlite";
|
||||
import * as schema from "./schema";
|
||||
import { env } from "../env";
|
||||
|
||||
const sqlite = new Database(env.DB_PATH);
|
||||
export default drizzle(sqlite);
|
||||
export default drizzle(sqlite, { schema });
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ export const interactions = sqliteTable("interactions", {
|
|||
id: integer().primaryKey({ autoIncrement: true }),
|
||||
uri: text().unique(),
|
||||
did: text(),
|
||||
post: text(),
|
||||
response: text(),
|
||||
muted: integer({ mode: "boolean" }),
|
||||
created_at: integer({ mode: "timestamp" }).default(sql`CURRENT_TIMESTAMP`),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import { isAuthorizedUser, logInteraction } from "../utils/interactions";
|
||||
import {
|
||||
isAuthorizedUser,
|
||||
logInteraction,
|
||||
getRecentInteractions,
|
||||
} from "../utils/interactions";
|
||||
import * as threadUtils from "../utils/thread";
|
||||
import modelPrompt from "../model/prompt.txt";
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
|
|
@ -131,10 +135,13 @@ export async function handler(post: Post): Promise<void> {
|
|||
return;
|
||||
}
|
||||
|
||||
await logInteraction(post);
|
||||
|
||||
if (await threadUtils.isThreadMuted(post)) {
|
||||
const isMuted = await threadUtils.isThreadMuted(post);
|
||||
if (isMuted) {
|
||||
logger.warn("Thread is muted.");
|
||||
await logInteraction(post, {
|
||||
responseText: null,
|
||||
wasMuted: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -151,11 +158,17 @@ export async function handler(post: Post): Promise<void> {
|
|||
await MemoryHandler.getBlocks(post.author.did),
|
||||
);
|
||||
|
||||
const recentInteractions = await getRecentInteractions(
|
||||
post.author.did,
|
||||
thread,
|
||||
);
|
||||
|
||||
const memory = yaml.dump({
|
||||
users_with_memory_blocks: {
|
||||
[env.HANDLE]: botMemory.parseBlocks(),
|
||||
[post.author.handle]: userMemory.parseBlocks(),
|
||||
},
|
||||
recent_interactions: recentInteractions,
|
||||
});
|
||||
|
||||
logger.log("Parsed memory blocks: ", memory);
|
||||
|
|
@ -167,6 +180,11 @@ export async function handler(post: Post): Promise<void> {
|
|||
if (responseText) {
|
||||
await sendResponse(post, responseText);
|
||||
}
|
||||
|
||||
await logInteraction(post, {
|
||||
responseText: responseText ?? null,
|
||||
wasMuted: false,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Error in post handler:", error);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { interactions } from "../db/schema";
|
||||
import type { Post } from "@skyware/bot";
|
||||
import { desc, notInArray } from "drizzle-orm";
|
||||
import { env } from "../env";
|
||||
import db from "../db";
|
||||
|
||||
|
|
@ -9,11 +10,41 @@ export function isAuthorizedUser(did: string) {
|
|||
: env.AUTHORIZED_USERS.includes(did as any);
|
||||
}
|
||||
|
||||
export async function logInteraction(post: Post): Promise<void> {
|
||||
await db.insert(interactions).values([{
|
||||
export async function logInteraction(
|
||||
post: Post,
|
||||
options: {
|
||||
responseText: string | null;
|
||||
wasMuted: boolean;
|
||||
},
|
||||
): Promise<void> {
|
||||
await db.insert(interactions).values([
|
||||
{
|
||||
uri: post.uri,
|
||||
did: post.author.did,
|
||||
}]);
|
||||
post: post.text,
|
||||
response: options.responseText,
|
||||
muted: options.wasMuted,
|
||||
},
|
||||
]);
|
||||
|
||||
console.log(`Logged interaction, initiated by @${post.author.handle}`);
|
||||
}
|
||||
|
||||
export async function getRecentInteractions(did: string, thread: Post[]) {
|
||||
const threadUris = thread.map((p) => p.uri);
|
||||
|
||||
const recentInteractions = await db.query.interactions.findMany({
|
||||
where: (interactions, { eq, and, notInArray }) =>
|
||||
and(
|
||||
eq(interactions.did, did),
|
||||
notInArray(interactions.uri, threadUris),
|
||||
),
|
||||
orderBy: (interactions, { desc }) => [desc(interactions.created_at)],
|
||||
limit: 5,
|
||||
});
|
||||
|
||||
return recentInteractions.map((i) => ({
|
||||
post: i.post,
|
||||
response: i.response,
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue