Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add features to the Solana Agent Kit #2458

Merged
merged 14 commits into from
Jan 17, 2025
Merged
13 changes: 2 additions & 11 deletions packages/plugin-solana-agentkit/src/actions/createToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import {
State,
type Action,
} from "@elizaos/core";

import { SolanaAgentKit } from "solana-agent-kit";

import { getSAK } from "../client";
export interface CreateTokenContent extends Content {
name: string;
uri: string;
Expand Down Expand Up @@ -103,14 +101,7 @@ export default {
}

elizaLogger.log("Init solana agent kit...");
const solanaPrivatekey = runtime.getSetting("SOLANA_PRIVATE_KEY");
const rpc = runtime.getSetting("SOLANA_RPC_URL");
const openAIKey = runtime.getSetting("OPENAI_API_KEY");
const solanaAgentKit = new SolanaAgentKit(
solanaPrivatekey,
rpc,
openAIKey
);
const solanaAgentKit = await getSAK(runtime);
try {
const deployedAddress = await solanaAgentKit.deployToken(
content.name,
Expand Down
153 changes: 153 additions & 0 deletions packages/plugin-solana-agentkit/src/actions/getTokenInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@

import { elizaLogger, } from "@elizaos/core";
import {
ActionExample,
Content,
HandlerCallback,
IAgentRuntime,
Memory,
ModelClass,
State,
type Action,
} from "@elizaos/core";
import { composeContext } from "@elizaos/core";
import { generateObjectDeprecated } from "@elizaos/core";
import { ACTIONS } from "solana-agent-kit";
import { getSAK } from "../client";

const GET_TOKEN_INFO_ACTION = ACTIONS.GET_TOKEN_DATA_ACTION;

export interface GetTokenInfoContent extends Content {
tokenAddress: string;
}

function isGetTokenInfoContent(
runtime: IAgentRuntime,
content: any
): content is GetTokenInfoContent {
elizaLogger.log("Content for transfer", content);
return (
typeof content.tokenAddress === "string"
);
}

const getTokenInfoTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.

Example response:
\`\`\`json
{
"tokenAddress": "SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa",
}
\`\`\`

{{recentMessages}}

Given the recent messages, extract the following information about the requested token:
- Token contract address

Respond with a JSON markdown block containing only the extracted values.`;

export default {
name: GET_TOKEN_INFO_ACTION.name,
similes: GET_TOKEN_INFO_ACTION.similes,
validate: async (runtime: IAgentRuntime, message: Memory) => {
elizaLogger.log("Validating get token info from user:", message.userId);

return false;
},
thearyanag marked this conversation as resolved.
Show resolved Hide resolved
description: GET_TOKEN_INFO_ACTION.description,
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: { [key: string]: unknown },
callback?: HandlerCallback
): Promise<boolean> => {
elizaLogger.log("Starting GET_TOKEN_INFO handler...");
const sak = await getSAK(runtime);

// Initialize or update state
if (!state) {
state = (await runtime.composeState(message)) as State;
} else {
state = await runtime.updateRecentMessageState(state);
}

// Compose get token info context
const getTokenInfoContext = composeContext({
state,
template: getTokenInfoTemplate,
});

// Generate get token info content
const content = await generateObjectDeprecated({
runtime,
context: getTokenInfoContext,
modelClass: ModelClass.LARGE,
});

// Validate get token info content
if (!isGetTokenInfoContent(runtime, content)) {
elizaLogger.error("Invalid content for GET_TOKEN_INFO action.");
if (callback) {
callback({
text: "Unable to process get token info request. Invalid content provided.",
content: { error: "Invalid get token info content" },
});
}
return false;
}

try {

const tokenData = await sak.getTokenDataByAddress(content.tokenAddress)

console.log("Token data:", tokenData);

if (callback) {
callback({
text: `Successfully retrieved token data for ${content.tokenAddress}`,
content: {
success: true,
tokenData: tokenData,
},
});
}

return true;
} catch (error) {
elizaLogger.error("Error during get token info:", error);
if (callback) {
callback({
text: `Error getting token info: ${error.message}`,
content: { error: error.message },
});
}
return false;
}
},

examples: [
[
{
user: "{{user1}}",
content: {
text: "Get token info for SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa",
},
},
{
user: "{{user2}}",
content: {
text: "Get token info for SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa",
action: "GET_TOKEN_INFO",
},
},
{
user: "{{user2}}",
content: {
text: "Successfully retrieved token info for SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa",
},
},
],
] as ActionExample[][],
} as Action;
177 changes: 177 additions & 0 deletions packages/plugin-solana-agentkit/src/actions/gibwork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { elizaLogger } from "@elizaos/core";
import {
ActionExample,
Content,
HandlerCallback,
IAgentRuntime,
Memory,
ModelClass,
State,
type Action,
} from "@elizaos/core";
import { composeContext } from "@elizaos/core";
import { generateObjectDeprecated } from "@elizaos/core";
import { ACTIONS } from "solana-agent-kit";
import { getSAK } from "../client";

const GIBWORK_ACTION = ACTIONS.CREATE_GIBWORK_TASK_ACTION;

export interface GibWorkContent extends Content {
title: string;
content: string;
requirements: string;
tags: string[];
tokenMintAddress: string;
tokenAmount: number;
}

function isGibWorkContent(
runtime: IAgentRuntime,
content: any
): content is GibWorkContent {
elizaLogger.log("Content for gibwork", content);
return (
typeof content.title === "string" &&
typeof content.content === "string" &&
typeof content.requirements === "string" &&
Array.isArray(content.tags) &&
typeof content.tokenMintAddress === "string" &&
typeof content.tokenAmount === "number"
);
}

const gibworkTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.

Example response:
\`\`\`json
{
"title": "Build a Solana dApp",
"content": "Create a simple Solana dApp with React frontend",
"requirements": "Experience with Rust and React",
"tags": ["solana", "rust", "react"],
"tokenMintAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"tokenAmount": 100
}
\`\`\`

{{recentMessages}}

Given the recent messages, extract the following information about the GibWork task:
- Title of the task
- Content/description of the task
- Requirements for the task
- Tags related to the task
- Token mint address for payment
- Token amount for payment

Respond with a JSON markdown block containing only the extracted values.`;

export default {
name: GIBWORK_ACTION.name,
similes: GIBWORK_ACTION.similes,
validate: async (runtime: IAgentRuntime, message: Memory) => {
elizaLogger.log("Validating gibwork task from user:", message.userId);
return false;
},
thearyanag marked this conversation as resolved.
Show resolved Hide resolved
description: GIBWORK_ACTION.description,
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: { [key: string]: unknown },
callback?: HandlerCallback
): Promise<boolean> => {
elizaLogger.log("Starting CREATE_GIBWORK_TASK handler...");
const sak = await getSAK(runtime);

// Initialize or update state
if (!state) {
state = (await runtime.composeState(message)) as State;
} else {
state = await runtime.updateRecentMessageState(state);
}

// Compose gibwork context
const gibworkContext = composeContext({
state,
template: gibworkTemplate,
});

// Generate gibwork content
const content = await generateObjectDeprecated({
runtime,
context: gibworkContext,
modelClass: ModelClass.LARGE,
});

// Validate gibwork content
if (!isGibWorkContent(runtime, content)) {
elizaLogger.error("Invalid content for CREATE_GIBWORK_TASK action.");
if (callback) {
callback({
text: "Unable to process GibWork task creation. Invalid content provided.",
content: { error: "Invalid gibwork content" },
});
}
return false;
}

try {
const gibworkResult = await sak.createGibworkTask(
content.title,
content.content,
content.requirements,
content.tags,
content.tokenMintAddress,
content.tokenAmount
);

console.log("GibWork task creation result:", gibworkResult);

if (callback) {
callback({
text: `Successfully created GibWork task: ${content.title}`,
content: {
success: true,
gibworkResult: gibworkResult,
},
});
}

return true;
} catch (error) {
elizaLogger.error("Error during GibWork task creation:", error);
if (callback) {
callback({
text: `Error creating GibWork task: ${error.message}`,
content: { error: error.message },
});
}
return false;
}
},

examples: [
[
{
user: "{{user1}}",
content: {
text: "Create a GibWork task for building a Solana dApp, offering 100 USDC",
},
},
{
user: "{{user2}}",
content: {
text: "Creating GibWork task",
action: "CREATE_GIBWORK_TASK",
},
},
{
user: "{{user2}}",
content: {
text: "Successfully created GibWork task: Build a Solana dApp",
},
},
],
] as ActionExample[][],
} as Action;
Loading
Loading