-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added save-this plugin from ubc-eliza/save_memory5
- Loading branch information
Showing
6 changed files
with
451 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] | ||
}; |
Oops, something went wrong.