diff --git a/packages/client-discord/src/templates.ts b/packages/client-discord/src/templates.ts
index e3dcd546122..ad02272479d 100644
--- a/packages/client-discord/src/templates.ts
+++ b/packages/client-discord/src/templates.ts
@@ -69,7 +69,7 @@ If {{agentName}} is conversing with a user and they have not asked to stop, it i
# INSTRUCTIONS: Choose the option that best describes {{agentName}}'s response to the last message. Ignore messages if they are addressed to someone else.
` + shouldRespondFooter;
-export const discordVoiceHandlerTemplate = `"You are {{agentName}}, an AI assistant capable of engaging in voice conversations.\n\nYour personality and background are as follows:\n\n\n{{bio}}\n\n\nRecent conversation context:\n\n{{recentMessages}}\n\n\nYou can perform the following actions:\n\n{{actions}}\n\n\nFollow these guidelines:\n1. Start with a very short (1-2 word) opening.\n2. Maintain a conversational tone consistent with your bio.\n3. Keep the response concise and suitable for voice output.\n\nFormat your response as plain text, don't include any analysis. If an action is needed, append it after a \"||\" delimiter.\n\nExample format (do not use this content):\nHello! I'd be happy to help you with your account balance. Let me check that for you right away. || CONTINUE\n\nNow, provide your response based on the context given."`;
+export const discordVoiceHandlerTemplate = `"You are {{agentName}}, an AI assistant capable of engaging in voice conversations.\n\nYour personality and background are as follows:\n\n\n{{bio}}\n\n\nRecent conversation context:\n\n{{recentMessages}}\n\n\nYou can perform the following actions:\n\n{{actions}}\n\n\nFollow these guidelines:\n1. Start with a very short (1-2 word) opening.\n2. Maintain a conversational tone consistent with your bio.\n3. Keep the response concise and suitable for voice output.\n\nFormat your response as plain text, don't include any analysis. If an action is needed, append it after a \"||\" delimiter.\n\nExample format (do not use this content):\nHello! I'd be happy to help you with your account balance. Let me check that for you right away. || CONTINUE\n\nNow, provide your response based on the context given and one of the actions: {{actionNames}}."`;
export const discordMessageHandlerTemplate =
// {{goals}}
diff --git a/packages/client-discord/src/voice.ts b/packages/client-discord/src/voice.ts
index a6ac81f31fe..db85c394495 100644
--- a/packages/client-discord/src/voice.ts
+++ b/packages/client-discord/src/voice.ts
@@ -735,6 +735,9 @@ export class VoiceManager extends EventEmitter {
const { roomId } = message;
let fullResponse = "";
let firstResponseSent = false;
+ let action = "NONE"; // Default action
+
+ elizaLogger.debug("context: ", context);
try {
const stream = await client.messages.stream({
@@ -748,15 +751,24 @@ export class VoiceManager extends EventEmitter {
// Helper function to process a complete text block
const processTextBlock = async (text: string): Promise => {
+ // Check for action delimiter
+ const parts = text.split("||");
+ const processText = parts[0].trim();
+ if (parts.length > 1) {
+ action = parts[1].trim();
+ }
+
console.time("textToSpeech");
const responseStream = await this.runtime
.getService(ServiceType.SPEECH_GENERATION)
- .generate(this.runtime, text);
+ .generate(this.runtime, processText);
console.timeEnd("textToSpeech");
if (responseStream) {
if (!firstResponseSent) {
- elizaLogger.debug(`First response sent at ms: ${Date.now()}`);
+ elizaLogger.debug(
+ `First response sent at ms: ${Date.now()}`
+ );
firstResponseSent = true;
}
console.time("audioPlayback");
@@ -814,6 +826,7 @@ export class VoiceManager extends EventEmitter {
source: "discord",
user: this.runtime.character.name,
inReplyTo: message.id,
+ action: action, // Add action to the content
},
roomId,
embedding: getEmbeddingZeroVector(),
@@ -823,6 +836,55 @@ export class VoiceManager extends EventEmitter {
await this.runtime.messageManager.createMemory(responseMemory);
state = await this.runtime.updateRecentMessageState(state);
await this.runtime.evaluate(message, state);
+
+ // Process actions if needed
+ const callback: HandlerCallback = async (content: Content) => {
+ const newResponseMemory: Memory = {
+ id: stringToUuid(
+ message.id + "-voice-response-" + Date.now()
+ ),
+ agentId: this.runtime.agentId,
+ userId: this.runtime.agentId,
+ content: {
+ ...content,
+ user: this.runtime.character.name,
+ inReplyTo: message.id,
+ },
+ roomId,
+ embedding: getEmbeddingZeroVector(),
+ };
+
+ if (newResponseMemory.content.text?.trim()) {
+ await this.runtime.messageManager.createMemory(
+ newResponseMemory
+ );
+ state =
+ await this.runtime.updateRecentMessageState(state);
+
+ const responseStream = await this.runtime
+ .getService(
+ ServiceType.SPEECH_GENERATION
+ )
+ .generate(this.runtime, content.text);
+
+ if (responseStream) {
+ await this.playAudioStream(
+ userId,
+ responseStream as Readable
+ );
+ }
+
+ }
+ return [newResponseMemory];
+ };
+
+ await this.runtime.processActions(
+ message,
+ [responseMemory],
+ state,
+ callback
+ );
+ this.runtime.evaluate(message, state, true);
}
console.timeEnd("saveResponseMemory");
@@ -866,6 +928,7 @@ export class VoiceManager extends EventEmitter {
channel: BaseGuildVoiceChannel,
state: State
): Promise {
+ return true;
if (userId === this.client.user?.id) return false;
const lowerMessage = message.toLowerCase();
const botName = this.client.user.username.toLowerCase();
@@ -876,6 +939,7 @@ export class VoiceManager extends EventEmitter {
if (
lowerMessage.includes(botName as string) ||
+ lowerMessage.includes("agent") ||
lowerMessage.includes(characterName) ||
lowerMessage.includes(
this.client.user?.tag.toLowerCase() as string
diff --git a/packages/plugin-depin/src/actions/listPredictions.ts b/packages/plugin-depin/src/actions/listPredictions.ts
index aadcce41228..f5780007967 100644
--- a/packages/plugin-depin/src/actions/listPredictions.ts
+++ b/packages/plugin-depin/src/actions/listPredictions.ts
@@ -8,7 +8,11 @@ import {
} from "@elizaos/core";
const formatPrediction = (prediction: any) => {
- const deadline = new Date(prediction.deadline).toLocaleString();
+ const deadline = new Date(prediction.deadline).toLocaleString('en-US', {
+ month: 'short',
+ day: 'numeric',
+ year: 'numeric'
+ });
return `"${prediction.statement}" (Due: ${deadline})`;
};
@@ -67,14 +71,9 @@ export const listPredictions: Action = {
)
.join("\n");
- const betFooter = `
-You can bet on them by saying
-"PREPARE A BET FOR PREDICTION , $SENTAI, , "
-`;
-
if (callback) {
callback({
- text: `🎯 Here are the active predictions:\n${formattedPredictions}\n\n${betFooter}`,
+ text: `🎯 Here are the active predictions:\n${formattedPredictions}`,
inReplyTo: message.id,
});
}
diff --git a/packages/plugin-depin/src/actions/placeBet.ts b/packages/plugin-depin/src/actions/placeBet.ts
index 650e207720c..7539c582281 100644
--- a/packages/plugin-depin/src/actions/placeBet.ts
+++ b/packages/plugin-depin/src/actions/placeBet.ts
@@ -12,16 +12,17 @@ import {
} from "@elizaos/core";
import {
+ approveAllowance,
placeBet as executeBlockchainBet,
getNetwork,
} from "../helpers/blockchain";
-const extractTxHash = (text: string): string | null => {
- // Match Ethereum/IoTeX transaction hash pattern
- const regex = /0x[a-fA-F0-9]{64}/;
- const match = text.match(regex);
- return match ? match[0] : null;
-};
+// const extractTxHash = (text: string): string | null => {
+// // Match Ethereum/IoTeX transaction hash pattern
+// const regex = /0x[a-fA-F0-9]{64}/;
+// const match = text.match(regex);
+// return match ? match[0] : null;
+// };
export const placeBet: Action = {
name: "PLACE_BET",
@@ -35,7 +36,7 @@ export const placeBet: Action = {
{
user: "user",
content: {
- text: "BET 123 APPROVED: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
+ text: "PLACE BET ON THE PREDICTION 1, 100 $SENTAI, it will rain tomorrow in London",
},
},
{
@@ -55,16 +56,16 @@ export const placeBet: Action = {
callback?: HandlerCallback
): Promise => {
try {
- const txHash = extractTxHash(message.content.text);
- if (!txHash) {
- if (callback) {
- callback({
- text: "I couldn't find a valid transaction hash in your message. Please provide the approval transaction hash.",
- inReplyTo: message.id,
- });
- }
- return false;
- }
+ // const txHash = extractTxHash(message.content.text);
+ // if (!txHash) {
+ // if (callback) {
+ // callback({
+ // text: "I couldn't find a valid transaction hash in your message. Please provide the approval transaction hash.",
+ // inReplyTo: message.id,
+ // });
+ // }
+ // return false;
+ // }
const betParams = await extractBetParamsFromContext(
runtime,
@@ -83,6 +84,12 @@ export const placeBet: Action = {
const network = getNetwork();
+ await approveAllowance(
+ runtime,
+ network,
+ Number(betParams.amount)
+ );
+
if (callback) {
callback({
text: "Processing your bet...",
@@ -96,13 +103,12 @@ export const placeBet: Action = {
betParams.predictionId,
betParams.outcome,
betParams.amount,
- betParams.bettor as `0x${string}`,
network
);
if (callback) {
callback({
- text: `Your bet has been placed successfully!\n\nPrediction: "${betParams.statement}"\nYour bet: ${betParams.outcome ? "Yes" : "No"}\nAmount: ${betResult.betAmount}\nBettor: ${betResult.bettor}\nTransaction: ${betResult.hash}`,
+ text: `Your bet has been placed successfully!\n\nPrediction: "${betParams.statement}"\nYour bet: ${betParams.outcome ? "Yes" : "No"}\nAmount: ${betResult.betAmount}}`,
inReplyTo: message.id,
});
}
@@ -137,7 +143,6 @@ export const placeBet: Action = {
};
interface BetParams {
- bettor: `0x${string}`;
amount: string;
outcome: boolean;
predictionId: number;
@@ -211,14 +216,12 @@ Deadline: Sat Jan 18 2025 12:00:00
- BET ON PREDICTION 1, 100 $SENTAI, true, 0x742d35Cc6634C0532925a3b844Bc454e4438f44e
- BetID: 123, 1. 0x742d35Cc6634C0532925a3b844Bc454e4438f44e, 100 $SENTAI, true. Tx data: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
-- BET 123 APPROVED: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
{
"reasoning": "The user is betting that it will rain tomorrow in London with 100 $SENTAI and he approved the bet.",
"statement": "It will rain tomorrow in London",
- "bettor": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"amount": "100",
"outcome": true,
"predictionId": 1
diff --git a/packages/plugin-depin/src/helpers/blockchain.ts b/packages/plugin-depin/src/helpers/blockchain.ts
index 7c6edbeac6b..b842597ce6b 100644
--- a/packages/plugin-depin/src/helpers/blockchain.ts
+++ b/packages/plugin-depin/src/helpers/blockchain.ts
@@ -135,7 +135,6 @@ export const placeBet = async (
predictionId: number,
outcome: boolean,
amount: string,
- bettor: `0x${string}`,
network: SupportedChain
) => {
const walletProvider = await initWalletProvider(runtime);
@@ -151,7 +150,7 @@ export const placeBet = async (
const betAmount = await getBetAmount(
amountInWei,
- bettor,
+ account,
account,
publicClient
);
@@ -162,13 +161,13 @@ export const placeBet = async (
abi: predictionAbi,
account,
functionName: "placeBetForAccount",
- args: [bettor, BigInt(predictionId), outcome, betAmount],
+ args: [account, BigInt(predictionId), outcome, betAmount],
});
const data = encodeFunctionData({
abi: predictionAbi,
functionName: "placeBetForAccount",
- args: [bettor, BigInt(predictionId), outcome, betAmount],
+ args: [account, BigInt(predictionId), outcome, betAmount],
});
const walletClient = walletProvider.getWalletClient(network);
@@ -193,7 +192,7 @@ export const placeBet = async (
return {
hash,
predictionId,
- bettor,
+ account,
betAmount: formatUnits(betAmount, decimals),
outcome,
};
@@ -202,6 +201,66 @@ export const placeBet = async (
}
};
+export const approveAllowance = async (
+ runtime: IAgentRuntime,
+ network: SupportedChain,
+ amount: number
+) => {
+ const walletProvider = await initWalletProvider(runtime);
+ const publicClient = walletProvider.getPublicClient(network);
+ const account = walletProvider.getAddress();
+
+ const decimals = await getDecimals(
+ runtime,
+ process.env.PREDICTION_TOKEN as `0x${string}`,
+ network
+ );
+ const amountInWei = parseUnits(amount.toString(), decimals);
+
+ await publicClient.simulateContract({
+ address: process.env.PREDICTION_TOKEN as `0x${string}`,
+ abi: erc20Abi,
+ account,
+ functionName: "approve",
+ args: [
+ process.env.BINARY_PREDICTION_CONTRACT_ADDRESS as `0x${string}`,
+ amountInWei,
+ ],
+ });
+
+ const data = encodeFunctionData({
+ abi: erc20Abi,
+ functionName: "approve",
+ args: [
+ process.env.BINARY_PREDICTION_CONTRACT_ADDRESS as `0x${string}`,
+ amountInWei,
+ ],
+ });
+
+ const walletClient = walletProvider.getWalletClient(network);
+ // @ts-ignore
+ const request = await walletClient.prepareTransactionRequest({
+ to: process.env.PREDICTION_TOKEN as `0x${string}`,
+ data,
+ account: walletClient.account,
+ });
+ // @ts-ignore
+ const serializedTransaction = await walletClient.signTransaction(request);
+ const hash = await walletClient.sendRawTransaction({
+ serializedTransaction,
+ });
+
+ const receipt = await publicClient.waitForTransactionReceipt({
+ hash,
+ });
+
+ if (receipt.status === "success") {
+ return hash;
+ } else {
+ throw new Error("Allowance approval failed");
+ }
+};
+
export const genTxDataForAllowance = async (
runtime: IAgentRuntime,
network: SupportedChain,
@@ -234,7 +293,10 @@ const getBetAmount = async (
address: process.env.PREDICTION_TOKEN as `0x${string}`,
abi: erc20Abi,
functionName: "allowance",
- args: [bettor, process.env.BINARY_PREDICTION_CONTRACT_ADDRESS as `0x${string}`],
+ args: [
+ bettor,
+ process.env.BINARY_PREDICTION_CONTRACT_ADDRESS as `0x${string}`,
+ ],
})) as bigint;
if (allowance <= BigInt(0)) {
diff --git a/packages/plugin-depin/src/index.ts b/packages/plugin-depin/src/index.ts
index bf40231177c..0a02bd17f39 100644
--- a/packages/plugin-depin/src/index.ts
+++ b/packages/plugin-depin/src/index.ts
@@ -6,18 +6,18 @@ export * from "./services/quicksilver";
import type { Plugin } from "@elizaos/core";
// import { depinProjects } from "./actions/depinProjects";
-// import { weather } from "./actions/weather";
+import { weather } from "./actions/weather";
// import { recentNews } from "./actions/recentNews";
-// import { weatherForecast } from "./actions/weatherForecast";
-// import { placeBet } from "./actions/placeBet";
+import { weatherForecast } from "./actions/weatherForecast";
+import { placeBet } from "./actions/placeBet";
// import { prepareBet } from "./actions/prepareBet";
-// import { listPredictions } from "./actions/listPredictions";
+import { listPredictions } from "./actions/listPredictions";
// import { depinDataProvider } from "./providers/depinData";
// import { weatherDataProvider } from "./providers/weatherDataProvider";
// import { weatherForecastProvider } from "./providers/weatherForecastProvider";
-// import { predictionEvaluator } from "./evaluators/predictions";
+import { predictionEvaluator } from "./evaluators/predictions";
// import PredictionResolver from "./services/PredictionResolver";
@@ -28,13 +28,16 @@ export const depinPlugin: Plugin = {
// Add providers here
],
evaluators: [
- // Add evaluators here
+ predictionEvaluator,
],
services: [
// Add services here
],
actions: [
- // Add actions here
+ weather,
+ weatherForecast,
+ listPredictions,
+ placeBet,
],
};