Skip to content

Commit

Permalink
added save-this plugin from ubc-eliza/save_memory5
Browse files Browse the repository at this point in the history
  • Loading branch information
metakai1 committed Dec 31, 2024
1 parent bad0e1c commit 6618a50
Show file tree
Hide file tree
Showing 6 changed files with 451 additions and 0 deletions.
24 changes: 24 additions & 0 deletions packages/plugin-save-this/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@ai16z/plugin-save-this",
"version": "0.0.1",
"description": "Plugin for saving important information from conversations",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"dependencies": {
"@ai16z/eliza": "workspace:*"
},
"scripts": {
"build": "tsc",
"example": "tsx examples/basic-usage.ts"
},
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"devDependencies": {
"tsx": "^4.7.0"
}
}
98 changes: 98 additions & 0 deletions packages/plugin-save-this/src/index copy.ts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// This plugin is for loading and saving data to the database written by Kai
// Claude, please help me develop this plugin as an exercise for me
// I want to learn the function of Evaluators, Providers, and Actions
// Please help me to develop this plugin step by step.
// we'll complete a basic save-memory action and have it prompt the user for what memories to save.

import { Plugin, AgentRuntime, knowledge, stringToUuid, settings, Action, elizaLogger } from "@ai16z/eliza";
import type { KnowledgeItem } from "@ai16z/eliza";

// Get user ID from environment variables
const USER_ID = settings.USER_ID || process.env.USER_ID;
if (!USER_ID) {
throw new Error("USER_ID must be set in environment variables");
}

const saveMemoryAction: Action = {
name: "save-memory",
description: "Store information in the agent's memory or load data into the memory system",
similes: [
"save a memory",
"store information",
"remember something",
"load data into memories",
"import data to memories",
"memorize this",
"keep track of this",
"add this to your memory"
],
examples: [[
{
user: "user",
content: {
text: "Save this memory: The sky is blue",
action: "save-memory",
},
},
], [
{
user: "user",
content: {
text: "load this data into memories: Important project deadline is next Friday",
action: "save-memory",
},
},
], [
{
user: "user",
content: {
text: "memorize that Alice prefers tea over coffee",
action: "save-memory",
},
},
]],
handler: async (runtime: AgentRuntime, message: any) => {
try {
const text = message.content.text;
elizaLogger.debug("Preprocessing text:", {
input: text,
length: text?.length,
});

// Create a knowledge item for the incoming text
const documentId = stringToUuid(text);
const knowledgeItem: KnowledgeItem = {
id: documentId,
content: {
text,
source: "user-input"
}
};

// Use the high-level knowledge.set function to create document and fragment memories
await knowledge.set(runtime, knowledgeItem);

return [{
userId: runtime.agentId,
agentId: runtime.agentId,
roomId: message.roomId,
content: {
text: "I've stored that information in my memory",
action: "save-memory",
},
}];
} catch (error) {
elizaLogger.error("Failed to create memory:", error);
throw new Error("Failed to store memory: " + error.message);
}
},
validate: async () => Promise.resolve(true),
};

export const databaseLoaderPlugin: Plugin = {
name: "database-loader",
description: "Plugin for loading and saving data to the database",
actions: [saveMemoryAction]
};

export { loadMemoriesFromFile } from './load-memories';
14 changes: 14 additions & 0 deletions packages/plugin-save-this/src/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface CalculatorPlugin {
name: string;
description: string;
initialize: (runtime: any) => void;
commands: {
add: (params: { a: number; b: number }) => number;
subtract: (params: { a: number; b: number }) => number;
multiply: (params: { a: number; b: number }) => number;
divide: (params: { a: number; b: number }) => number;
};
}

export const calculatorPlugin: CalculatorPlugin;
export default calculatorPlugin;
163 changes: 163 additions & 0 deletions packages/plugin-save-this/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { Plugin, AgentRuntime, knowledge, stringToUuid, generateText, settings, Action, elizaLogger, MemoryManager, EvaluationExample } from "@ai16z/eliza";
import type { KnowledgeItem } from "@ai16z/eliza";

import {
Evaluator,
IAgentRuntime,
Memory,
State,
Provider,
HandlerCallback,
} from "@ai16z/eliza";

const saveThisAction: Action = {
name: "SAVE_THIS",
description: "Stores important information from the conversation in the agent's long-term knowledge base",
similes: [],
validate: async (runtime: IAgentRuntime, message: Memory) => {
return Promise.resolve(!!message?.content?.text);
},

handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: { [key: string]: unknown },
callback?: HandlerCallback
) => {
try {

elizaLogger.info(state);

// Only proceed if explicitly requested via state
if (!state?.shouldSave) {
elizaLogger.info('[SaveThisAction] handler.abort - Save not requested in state');
return state; // Important: Return the unchanged state
}
// Get recent messages
const recentMessages = await runtime.messageManager.getMemories({
roomId: message.roomId,
count: 7,
unique: false
});

// combine the text from recent messages into a string
const recentMessagesText = recentMessages
.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0))
.map(msg => msg.content.text)
.join("\n\n");

if (callback) {
await callback({
text: "Summary in progress...",
content: {
text: "Summary in progress..."
}
}, []);
} else {
elizaLogger.error('[SaveThisAction] No callback');
}

elizaLogger.info("Recent messages:", recentMessagesText);

const saveKnowledge = await generateText({
runtime,
context: `\
The following messages are from a conversation between an ai agent and a user.
The most recent 7 messages are sent to this query, ordered from oldest to newest. Some messages from
the user may be included. The last message is the "save this" request from the user, which is then triggers this query. Realize that conversation history may include agent responses \
from previous user queries. You should determine by the flow of conversation what
information the user is wanting to save. Prioritize saving the most recent agent response.
The user my also append additional words to the "save this" request, which may be relevant in
deciding what information for you to save. For example, he/she could say "save this information about cars".
By those words, you can determine what information the wants to focus on.
Save instructions: Do not store information about the user. Focus on saving knowledge, not conversation
history. Don't save what the conversation is about, but rather the facts and details contained in the
responses by the agent, retaining style and tone. Save the memory as a paragraph of text, not in point
or bullet form. Here are the messages:
${recentMessagesText}`,
modelClass: "medium"
});

//elizaLogger.info("Saved knowledge: from model", saveKnowledge);

// Save the message content to the knowledge base
const memoryToSave = {
id: stringToUuid(`memory_${Date.now()}`),
content: {
text: saveKnowledge,
source: "agentdata"
}
};

//elizaLogger.info("Memory to save:", memoryToSave);

await knowledge.set(runtime as AgentRuntime, memoryToSave);

if (callback) {
callback({
// text: `I've stored this information: "${saveKnowledge}"`,
text: `I've stored the information for you`,
});
return;
}

} catch (error) {
elizaLogger.error('[Action] handler.error:', error);
if (callback) {
await callback({
text: "Sorry, I encountered an error while saving.",
content: {
success: false,
text: "Sorry, I encountered an error while saving."
}
}, []);
}
return false;
}
},
examples: []
};

export const saveThisProvider: Provider = {
get: async (runtime: IAgentRuntime, message: Memory, state?: State) => {
const text = message.content?.text?.toLowerCase() || '';

// Trigger if message starts with "save this"
if (text.trim().startsWith('save this')) {
// Modify state in place first
if (state) {
state.shouldSave = true;
}

if(!state.shouldSave) {
elizaLogger.error('saveThisProvider: state.shouldSave is faised');
}

// Then trigger the SAVE_THIS action
await runtime.processActions(message, [{
id: stringToUuid(`save_this_response_${Date.now()}`),
userId: message.userId,
agentId: message.agentId,
roomId: message.roomId,
content: {
action: 'SAVE_THIS',
text: 'Saving previous message...'
}
}]);
}

return;
}
};


export const saveThisPlugin: Plugin = {
name: "save-this",
description: "Plugin for saving important information from conversations using a save this keyphrase",
actions: [saveThisAction],
evaluators: [],
providers: [saveThisProvider]
};
Loading

0 comments on commit 6618a50

Please sign in to comment.