Skip to content

Commit 0fbec0f

Browse files
authored
Merge pull request #248 from MarcoMandar/main
trust integration
2 parents 9a04908 + fc072eb commit 0fbec0f

File tree

8 files changed

+514
-44
lines changed

8 files changed

+514
-44
lines changed

packages/client-telegram/src/messageManager.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,7 @@ export class MessageManager {
397397

398398
// Decide whether to respond
399399
const shouldRespond = await this._shouldRespond(message, state);
400-
if (!shouldRespond) return;
401-
400+
if (shouldRespond) {
402401
// Generate response
403402
const context = composeContext({
404403
state,
@@ -463,7 +462,6 @@ export class MessageManager {
463462

464463
// Update state after response
465464
state = await this.runtime.updateRecentMessageState(state);
466-
await this.runtime.evaluate(memory, state);
467465

468466
// Handle any resulting actions
469467
await this.runtime.processActions(
@@ -472,6 +470,9 @@ export class MessageManager {
472470
state,
473471
callback
474472
);
473+
}
474+
475+
await this.runtime.evaluate(memory, state, shouldRespond);
475476
} catch (error) {
476477
console.error("❌ Error handling message:", error);
477478
console.error("Error sending message:", error);

packages/core/src/models.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const models: Models = {
3131
},
3232
endpoint: "https://api.anthropic.com/v1",
3333
model: {
34-
[ModelClass.SMALL]: "claude-3-5-sonnet-20241022",
34+
[ModelClass.SMALL]: "claude-3-5-haiku",
3535
[ModelClass.MEDIUM]: "claude-3-5-sonnet-20241022",
3636
[ModelClass.LARGE]: "claude-3-opus-20240229",
3737
},

packages/plugin-solana/src/adapters/trustScoreDatabase.ts

+66
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,72 @@ export class TrustScoreDatabase {
403403
}
404404
}
405405

406+
// get Or Create Recommender with discord id
407+
408+
/**
409+
* Retrieves an existing recommender or creates a new one if not found.
410+
* Also initializes metrics for the recommender if they haven't been initialized yet.
411+
* @param discordId Discord ID of the recommender
412+
* @returns Recommender object with all details, or null if failed
413+
*/
414+
415+
async getOrCreateRecommenderWithDiscordId(
416+
discordId: string
417+
): Promise<Recommender | null> {
418+
try {
419+
// Begin a transaction
420+
const transaction = this.db.transaction(() => {
421+
// Attempt to retrieve the recommender
422+
const existingRecommender = this.getRecommender(discordId);
423+
if (existingRecommender) {
424+
// Recommender exists, ensure metrics are initialized
425+
this.initializeRecommenderMetrics(existingRecommender.id!);
426+
return existingRecommender;
427+
}
428+
429+
// Recommender does not exist, create a new one
430+
const newRecommender = {
431+
id: uuidv4(),
432+
address: discordId,
433+
discordId: discordId,
434+
};
435+
const newRecommenderId = this.addRecommender(newRecommender);
436+
if (!newRecommenderId) {
437+
throw new Error("Failed to add new recommender.");
438+
}
439+
440+
// Initialize metrics for the new recommender
441+
const metricsInitialized =
442+
this.initializeRecommenderMetrics(newRecommenderId);
443+
if (!metricsInitialized) {
444+
throw new Error(
445+
"Failed to initialize recommender metrics."
446+
);
447+
}
448+
449+
// Retrieve and return the newly created recommender
450+
const recommender = this.getRecommender(newRecommenderId);
451+
if (!recommender) {
452+
throw new Error(
453+
"Failed to retrieve the newly created recommender."
454+
);
455+
}
456+
457+
return recommender;
458+
});
459+
460+
// Execute the transaction and return the recommender
461+
const recommenderResult = transaction();
462+
return recommenderResult;
463+
} catch (error) {
464+
console.error(
465+
"Error in getOrCreateRecommenderWithDiscordId:",
466+
error
467+
);
468+
return null;
469+
}
470+
}
471+
406472
/**
407473
* Initializes metrics for a recommender if not present.
408474
* @param recommenderId Recommender's UUID

packages/plugin-solana/src/evaluators/trust.ts

+146-27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { composeContext } from "@ai16z/eliza/src/context.ts";
2-
import { generateObjectArray, generateTrueOrFalse } from "@ai16z/eliza/src/generation.ts";
2+
import {
3+
generateObjectArray,
4+
generateTrueOrFalse,
5+
} from "@ai16z/eliza/src/generation.ts";
36
import { MemoryManager } from "@ai16z/eliza/src/memory.ts";
47
import { booleanFooter } from "@ai16z/eliza/src/parsing.ts";
58
import {
@@ -11,6 +14,11 @@ import {
1114
Evaluator,
1215
} from "@ai16z/eliza/src/types.ts";
1316
import { stringToUuid } from "@ai16z/eliza/src/uuid.ts";
17+
import { TrustScoreManager } from "../providers/trustScoreProvider.ts";
18+
import { TokenProvider } from "../providers/token.ts";
19+
import { WalletProvider } from "../providers/wallet.ts";
20+
import { TrustScoreDatabase } from "../adapters/trustScoreDatabase.ts";
21+
import { Connection, PublicKey } from "@solana/web3.js";
1422

1523
const shouldProcessTemplate =
1624
`# Task: Decide if the recent messages should be processed for token recommendations.
@@ -34,8 +42,7 @@ export const formatRecommendations = (recommendations: Memory[]) => {
3442
return finalMessageStrings;
3543
};
3644

37-
const recommendationTemplate =
38-
`TASK: Extract recommendations to buy or sell memecoins from the conversation as an array of objects in JSON format.
45+
const recommendationTemplate = `TASK: Extract recommendations to buy or sell memecoins from the conversation as an array of objects in JSON format.
3946
4047
Memecoins usually have a ticker and a contract address. Additionally, recommenders may make recommendations with some amount of conviction. The amount of conviction in their recommendation can be none, low, medium, or high. Recommenders can make recommendations to buy, not buy, sell and not sell.
4148
@@ -74,7 +81,7 @@ Response should be a JSON object array inside a JSON markdown block. Correct res
7481
\`\`\``;
7582

7683
async function handler(runtime: IAgentRuntime, message: Memory) {
77-
console.log("Evaluating for trust")
84+
console.log("Evaluating for trust");
7885
const state = await runtime.composeState(message);
7986

8087
const { agentId, roomId } = state;
@@ -92,10 +99,10 @@ async function handler(runtime: IAgentRuntime, message: Memory) {
9299
});
93100

94101
if (!shouldProcess) {
95-
console.log("Skipping process")
102+
console.log("Skipping process");
96103
return [];
97104
}
98-
105+
99106
// Get recent recommendations
100107
const recommendationsManager = new MemoryManager({
101108
runtime,
@@ -122,34 +129,138 @@ async function handler(runtime: IAgentRuntime, message: Memory) {
122129
modelClass: ModelClass.LARGE,
123130
});
124131

125-
console.log("recommendations", recommendations)
132+
console.log("recommendations", recommendations);
126133

127134
if (!recommendations) {
128135
return [];
129136
}
130137

131138
// If the recommendation is already known or corrupted, remove it
132-
const filteredRecommendations = recommendations
133-
.filter((rec) => {
139+
const filteredRecommendations = recommendations.filter((rec) => {
140+
return (
141+
!rec.alreadyKnown &&
142+
(rec.ticker || rec.contractAddress) &&
143+
rec.recommender &&
144+
rec.conviction &&
145+
rec.recommender.trim() !== ""
146+
);
147+
});
148+
149+
for (const rec of filteredRecommendations) {
150+
// create the wallet provider and token provider
151+
const walletProvider = new WalletProvider(
152+
new Connection("https://api.mainnet-beta.solana.com"),
153+
new PublicKey(runtime.getSetting("WALLET_PUBLIC_KEY"))
154+
);
155+
const tokenProvider = new TokenProvider(
156+
rec.contractAddress,
157+
walletProvider
158+
);
159+
160+
// TODO: Check to make sure the contract address is valid, it's the right one, etc
161+
162+
//
163+
if (!rec.contractAddress) {
164+
const tokenAddress = await tokenProvider.getTokenFromWallet(
165+
runtime,
166+
rec.ticker
167+
);
168+
rec.contractAddress = tokenAddress;
169+
if (!tokenAddress) {
170+
// try to search for the symbol and return the contract address with they highest liquidity and market cap
171+
const result = await tokenProvider.searchDexScreenerData(
172+
rec.ticker
173+
);
174+
const tokenAddress = result?.baseToken?.address;
175+
rec.contractAddress = tokenAddress;
176+
if (!tokenAddress) {
177+
console.warn("Could not find contract address for token");
178+
continue;
179+
}
180+
}
181+
}
182+
183+
// create the trust score manager
184+
185+
const trustScoreDb = new TrustScoreDatabase(runtime.databaseAdapter.db);
186+
const trustScoreManager = new TrustScoreManager(
187+
tokenProvider,
188+
trustScoreDb
189+
);
190+
191+
// get actors from the database
192+
const participants =
193+
await runtime.databaseAdapter.getParticipantsForRoom(
194+
message.roomId
195+
);
196+
197+
// find the first user Id from a user with the username that we extracted
198+
const user = participants.find(async (actor) => {
199+
const user = await runtime.databaseAdapter.getAccountById(actor);
134200
return (
135-
!rec.alreadyKnown &&
136-
(rec.ticker || rec.contractAddress) &&
137-
rec.recommender &&
138-
rec.recommender.trim() !== ""
201+
user.name.toLowerCase().trim() ===
202+
rec.recommender.toLowerCase().trim()
139203
);
140-
})
204+
});
205+
206+
if (!user) {
207+
console.warn("Could not find user: ", rec.recommender);
208+
continue;
209+
}
210+
211+
const account = await runtime.databaseAdapter.getAccountById(user);
212+
const userId = account.id;
141213

142-
for (const rec of filteredRecommendations) {
143-
console.log("Recommendation: ", rec);
144214
const recMemory = {
145-
userId: stringToUuid(rec.recommender),
215+
userId,
146216
agentId,
147217
content: { text: JSON.stringify(rec) },
148218
roomId,
149219
createdAt: Date.now(),
150220
};
151221

152222
await recommendationsManager.createMemory(recMemory, true);
223+
224+
// buy, dont buy, sell, dont sell
225+
226+
const buyAmounts = await this.tokenProvider.getBuyAmounts();
227+
228+
let buyAmount = buyAmounts[rec.conviction.toLowerCase().trim()];
229+
if (!buyAmount) {
230+
// handle annoying cases
231+
// for now just put in 10 sol
232+
buyAmount = 10;
233+
}
234+
235+
// TODO: is this is a buy, sell, dont buy, or dont sell?
236+
const shouldTrade = await this.tokenProvider.shouldTrade();
237+
238+
if (!shouldTrade) {
239+
console.warn(
240+
"There might be a problem with the token, not trading"
241+
);
242+
continue;
243+
}
244+
245+
switch (rec.type) {
246+
case "buy":
247+
// for now, lets just assume buy only, but we should implement
248+
await trustScoreManager.createTradePerformance(
249+
runtime,
250+
rec.contractAddress,
251+
userId,
252+
{
253+
buy_amount: rec.buyAmount,
254+
is_simulation: true,
255+
}
256+
);
257+
break;
258+
case "sell":
259+
case "dont_sell":
260+
case "dont_buy":
261+
console.warn("Not implemented");
262+
break;
263+
}
153264
}
154265

155266
return filteredRecommendations;
@@ -167,7 +278,7 @@ export const trustEvaluator: Evaluator = {
167278
runtime: IAgentRuntime,
168279
message: Memory
169280
): Promise<boolean> => {
170-
if(message.content.text.length < 5) {
281+
if (message.content.text.length < 5) {
171282
return false;
172283
}
173284

@@ -187,15 +298,21 @@ None`,
187298
messages: [
188299
{
189300
user: "{{user1}}",
190-
content: { text: "Yo, have you checked out $SOLARUG? Dope new yield aggregator on Solana." },
301+
content: {
302+
text: "Yo, have you checked out $SOLARUG? Dope new yield aggregator on Solana.",
303+
},
191304
},
192305
{
193306
user: "{{user2}}",
194-
content: { text: "Nah, I'm still trying to wrap my head around how yield farming even works haha. Is it risky?" },
307+
content: {
308+
text: "Nah, I'm still trying to wrap my head around how yield farming even works haha. Is it risky?",
309+
},
195310
},
196311
{
197312
user: "{{user1}}",
198-
content: { text: "I mean, there's always risk in DeFi, but the $SOLARUG devs seem legit. Threw a few sol into the FCweoTfJ128jGgNEXgdfTXdEZVk58Bz9trCemr6sXNx9 vault, farming's been smooth so far." },
313+
content: {
314+
text: "I mean, there's always risk in DeFi, but the $SOLARUG devs seem legit. Threw a few sol into the FCweoTfJ128jGgNEXgdfTXdEZVk58Bz9trCemr6sXNx9 vault, farming's been smooth so far.",
315+
},
199316
},
200317
] as ActionExample[],
201318
outcome: `\`\`\`json
@@ -228,7 +345,9 @@ Recommendations about the actors:
228345
},
229346
{
230347
user: "{{user2}}",
231-
content: { text: "Idk man, feels like there's a new 'vault' or 'reserve' token every week on Sol. What happened to $COPETOKEN and $SOYLENT that you were shilling before?" },
348+
content: {
349+
text: "Idk man, feels like there's a new 'vault' or 'reserve' token every week on Sol. What happened to $COPETOKEN and $SOYLENT that you were shilling before?",
350+
},
232351
},
233352
{
234353
user: "{{user1}}",
@@ -299,7 +418,7 @@ None`,
299418
"alreadyKnown": false
300419
}
301420
]
302-
\`\`\``
421+
\`\`\``,
303422
},
304423

305424
{
@@ -353,7 +472,7 @@ None
353472
"alreadyKnown": false
354473
}
355474
]
356-
\`\`\``
475+
\`\`\``,
357476
},
358477

359478
{
@@ -408,7 +527,7 @@ None`,
408527
"alreadyKnown": false
409528
}
410529
]
411-
\`\`\``
412-
}
530+
\`\`\``,
531+
},
413532
],
414-
};
533+
};

0 commit comments

Comments
 (0)