fix: json

This commit is contained in:
aryan
2024-12-05 20:28:02 +05:30
parent c31146031a
commit 205ff4891c
5 changed files with 155 additions and 36 deletions

View File

@@ -15,6 +15,7 @@
"dependencies": {
"@bonfida/spl-name-service": "^3.0.7",
"@langchain/core": "^0.3.18",
"@langchain/groq": "^0.1.2",
"@langchain/openai": "^0.3.13",
"@metaplex-foundation/mpl-core": "^1.1.1",
"@metaplex-foundation/mpl-token-metadata": "^3.3.0",

46
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ importers:
'@langchain/core':
specifier: ^0.3.18
version: 0.3.18(openai@4.72.0(zod@3.23.8))
'@langchain/groq':
specifier: ^0.1.2
version: 0.1.2(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))
'@langchain/openai':
specifier: ^0.3.13
version: 0.3.13(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))
@@ -49,7 +52,7 @@ importers:
version: 4.0.1
langchain:
specifier: ^0.3.6
version: 0.3.6(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))(axios@1.7.7)(openai@4.72.0(zod@3.23.8))
version: 0.3.6(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))(@langchain/groq@0.1.2(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8))))(axios@1.7.7)(openai@4.72.0(zod@3.23.8))
typedoc:
specifier: ^0.26.11
version: 0.26.11(typescript@5.6.3)
@@ -95,6 +98,12 @@ packages:
resolution: {integrity: sha512-IEZCrFs1Xd0J2FTH1D3Lnm3/Yk2r8LSpwDeLYwcCom3rNAK5k4mKQ2rwIpNq3YuqBdrTNMKRO+PopjkP1SB17A==}
engines: {node: '>=18'}
'@langchain/groq@0.1.2':
resolution: {integrity: sha512-bgQ9yGoNHOwG6LG2ngGvSNxF/1U1c1u3vKmFWmzecFIcBoQQOJY0jb0MrL3g1uTife0Sr3zxkWKXQg2aK/U4Sg==}
engines: {node: '>=18'}
peerDependencies:
'@langchain/core': '>=0.2.21 <0.4.0'
'@langchain/openai@0.3.13':
resolution: {integrity: sha512-lfiauYttb1Vv1GVGDNZlse8475RUsKm9JJ7X9kMVtYoOQnK8xxzMVSrpW7HYLmJokrtVgF6STwRzNJI2gZ3uBw==}
engines: {node: '>=18'}
@@ -609,6 +618,9 @@ packages:
graphemesplit@2.4.4:
resolution: {integrity: sha512-lKrpp1mk1NH26USxC/Asw4OHbhSQf5XfrWZ+CDv/dFVvd1j17kFgMotdJvOesmHkbFX9P9sBfpH8VogxOWLg8w==}
groq-sdk@0.5.0:
resolution: {integrity: sha512-RVmhW7qZ+XZoy5fIuSdx/LGQJONpL8MHgZEW7dFwTdgkzStub2XQx6OKv28CHogijdwH41J+Npj/z2jBPu3vmw==}
hast-util-to-html@9.0.3:
resolution: {integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==}
@@ -963,6 +975,10 @@ packages:
vfile@6.0.3:
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
web-streams-polyfill@4.0.0-beta.3:
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
engines: {node: '>= 14'}
@@ -1078,6 +1094,16 @@ snapshots:
transitivePeerDependencies:
- openai
'@langchain/groq@0.1.2(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))':
dependencies:
'@langchain/core': 0.3.18(openai@4.72.0(zod@3.23.8))
'@langchain/openai': 0.3.13(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))
groq-sdk: 0.5.0
zod: 3.23.8
zod-to-json-schema: 3.23.5(zod@3.23.8)
transitivePeerDependencies:
- encoding
'@langchain/openai@0.3.13(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))':
dependencies:
'@langchain/core': 0.3.18(openai@4.72.0(zod@3.23.8))
@@ -1667,6 +1693,19 @@ snapshots:
js-base64: 3.7.7
unicode-trie: 2.0.0
groq-sdk@0.5.0:
dependencies:
'@types/node': 18.19.64
'@types/node-fetch': 2.6.12
abort-controller: 3.0.0
agentkeepalive: 4.5.0
form-data-encoder: 1.7.2
formdata-node: 4.4.1
node-fetch: 2.7.0
web-streams-polyfill: 3.3.3
transitivePeerDependencies:
- encoding
hast-util-to-html@9.0.3:
dependencies:
'@types/hast': 3.0.4
@@ -1733,7 +1772,7 @@ snapshots:
jsonpointer@5.0.1: {}
langchain@0.3.6(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))(axios@1.7.7)(openai@4.72.0(zod@3.23.8)):
langchain@0.3.6(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))(@langchain/groq@0.1.2(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8))))(axios@1.7.7)(openai@4.72.0(zod@3.23.8)):
dependencies:
'@langchain/core': 0.3.18(openai@4.72.0(zod@3.23.8))
'@langchain/openai': 0.3.13(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))
@@ -1749,6 +1788,7 @@ snapshots:
zod: 3.23.8
zod-to-json-schema: 3.23.5(zod@3.23.8)
optionalDependencies:
'@langchain/groq': 0.1.2(@langchain/core@0.3.18(openai@4.72.0(zod@3.23.8)))
axios: 1.7.7
transitivePeerDependencies:
- encoding
@@ -2028,6 +2068,8 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.2
web-streams-polyfill@3.3.3: {}
web-streams-polyfill@4.0.0-beta.3: {}
webidl-conversions@3.0.1: {}

View File

@@ -1,12 +1,13 @@
import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../index";
import { PublicKey } from "@solana/web3.js";
import { launchPumpFunToken } from "../tools";
import { PumpFunTokenOptions } from "../types";
import { toJSON } from "../utils/toJSON";
export class SolanaBalanceTool extends Tool {
name = "solana_balance";
description = "Get the balance of a Solana wallet or token account. Input can be a token address or empty for SOL balance.";
description =
"Get the balance of a Solana wallet or token account. Input can be a token address or empty for SOL balance.";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -24,8 +25,9 @@ export class SolanaBalanceTool extends Tool {
export class SolanaTransferTool extends Tool {
name = "solana_transfer";
description = "Transfer tokens or SOL to another address. Input should be JSON string with: {to: string, amount: number, mint?: string}";
description =
"Transfer tokens or SOL to another address. Input should be JSON string with: {to: string, amount: number, mint?: string}";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -35,7 +37,7 @@ export class SolanaTransferTool extends Tool {
const { to, amount, mint } = JSON.parse(input);
const recipient = new PublicKey(to);
const mintAddress = mint ? new PublicKey(mint) : undefined;
await this.solanaKit.transfer(recipient, amount, mintAddress);
return `Successfully transferred ${amount} to ${to}`;
} catch (error: any) {
@@ -46,15 +48,16 @@ export class SolanaTransferTool extends Tool {
export class SolanaDeployTokenTool extends Tool {
name = "solana_deploy_token";
description = "Deploy a new SPL token. Input should be JSON string with: {decimals?: number, initialSupply?: number}";
description =
"Deploy a new SPL token. Input should be JSON string with: {decimals?: number, initialSupply?: number}";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
try {
const validJson = input
const validJson = input
.replace(/([a-zA-Z0-9_]+):/g, '"$1":') // Add quotes around keys
.trim();
const { decimals = 9 } = JSON.parse(validJson);
@@ -68,8 +71,9 @@ export class SolanaDeployTokenTool extends Tool {
export class SolanaDeployCollectionTool extends Tool {
name = "solana_deploy_collection";
description = "Deploy a new NFT collection. Input should be JSON with: {name: string, uri: string, royaltyBasisPoints?: number, creators?: Array<{address: string, percentage: number}>}";
description =
"Deploy a new NFT collection. Input should be JSON with: {name: string, uri: string, royaltyBasisPoints?: number, creators?: Array<{address: string, percentage: number}>}";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -87,8 +91,9 @@ export class SolanaDeployCollectionTool extends Tool {
export class SolanaMintNFTTool extends Tool {
name = "solana_mint_nft";
description = "Mint a new NFT in a collection. Input should be JSON with: {collectionMint: string, metadata: {name: string, symbol: string, uri: string}, recipient?: string}";
description =
"Mint a new NFT in a collection. Input should be JSON with: {collectionMint: string, metadata: {name: string, symbol: string, uri: string}, recipient?: string}";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -111,15 +116,17 @@ export class SolanaMintNFTTool extends Tool {
export class SolanaTradeTool extends Tool {
name = "solana_trade";
description = "Swap tokens using Jupiter Exchange. Input should be JSON with: {outputMint: string, inputAmount: number, inputMint?: string, slippageBps?: number}";
description =
"Swap tokens using Jupiter Exchange. Input should be JSON with: {outputMint: string, inputAmount: number, inputMint?: string, slippageBps?: number}";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
try {
const { outputMint, inputAmount, inputMint, slippageBps } = JSON.parse(input);
const { outputMint, inputAmount, inputMint, slippageBps } =
JSON.parse(input);
const tx = await this.solanaKit.trade(
new PublicKey(outputMint),
inputAmount,
@@ -136,7 +143,7 @@ export class SolanaTradeTool extends Tool {
export class SolanaRequestFundsTool extends Tool {
name = "solana_request_funds";
description = "Request SOL from Solana faucet (devnet/testnet only)";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -153,8 +160,9 @@ export class SolanaRequestFundsTool extends Tool {
export class SolanaRegisterDomainTool extends Tool {
name = "solana_register_domain";
description = "Register a .sol domain name. Input should be JSON with: {name: string, spaceKB?: number}";
description =
"Register a .sol domain name. Input should be JSON with: {name: string, spaceKB?: number}";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -173,7 +181,7 @@ export class SolanaRegisterDomainTool extends Tool {
export class SolanaGetWalletAddressTool extends Tool {
name = "solana_get_wallet_address";
description = "Get the wallet address of the agent";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
@@ -183,25 +191,64 @@ export class SolanaGetWalletAddressTool extends Tool {
}
}
export class SolanaPumpfunTokenLaunch extends Tool {
export class SolanaPumpfunTokenLaunchTool extends Tool {
name = "solana_launch_pumpfun_token";
description = "Launch a new token on Pump.fun via Solana Agent Kit. Input should be JSON with: {tokenName: string, tokenTicker: string, description?: string, twitter?: string, telegram?: string, website?: string, imageUrl?: string, initialLiquiditySOL?: number, mintAddress?: string}";
description = "Launch a new token on Pump.fun via Solana Agent Kit. Requires a JSON input with tokenName and tokenTicker, with optional fields for description, twitter, telegram, website, imageUrl, initialLiquiditySOL, and mintAddress.";
constructor(private solanaKit: SolanaAgentKit) {
super();
super();
}
async _call(input: string): Promise<string> {
try {
const options = JSON.parse(input);
await launchPumpFunToken(this.solanaKit, options.tokenName, options.tokenTicker, options);
return "Token launched successfully on Pump.fun";
} catch (error: any) {
return `Error launching token: ${error.message}`;
}
private validateInput(input : any): void {
if (!input.tokenName || typeof input.tokenName !== 'string') {
throw new Error('tokenName is required and must be a string');
}
if (!input.tokenTicker || typeof input.tokenTicker !== 'string') {
throw new Error('tokenTicker is required and must be a string');
}
if (input.initialLiquiditySOL !== undefined && typeof input.initialLiquiditySOL !== 'number') {
throw new Error('initialLiquiditySOL must be a number when provided');
}
}
protected async _call(input: string): Promise<string> {
try {
// Parse and normalize input
const parsedInput = toJSON(input);
// Validate the input
this.validateInput(parsedInput);
// Launch token with validated input
await this.solanaKit.launchPumpFunToken(
parsedInput.tokenName,
parsedInput.tokenTicker,
{
description: parsedInput.description,
twitter: parsedInput.twitter,
telegram: parsedInput.telegram,
website: parsedInput.website,
imageUrl: parsedInput.imageUrl,
initialLiquiditySOL: parsedInput.initialLiquiditySOL,
}
);
return JSON.stringify({
status: "success",
message: "Token launched successfully on Pump.fun",
tokenName: parsedInput.tokenName,
tokenTicker: parsedInput.tokenTicker
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR"
});
}
}
}
// Updated createSolanaTools function
export function createSolanaTools(solanaKit: SolanaAgentKit) {
return [
new SolanaBalanceTool(solanaKit),
@@ -213,6 +260,6 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaRequestFundsTool(solanaKit),
new SolanaRegisterDomainTool(solanaKit),
new SolanaGetWalletAddressTool(solanaKit),
new SolanaPumpfunTokenLaunch(solanaKit)
new SolanaPumpfunTokenLaunchTool(solanaKit),
];
}

View File

@@ -39,12 +39,15 @@ async function uploadMetadata(
finalFormData.append('file', files.file);
}
console.log("Final form data:", finalFormData);
const metadataResponse = await fetch("https://pump.fun/api/ipfs", {
method: "POST",
body: finalFormData
});
if (!metadataResponse.ok) {
console.log("Metadata response:", await metadataResponse.json());
throw new Error(`Metadata upload failed: ${metadataResponse.statusText}`);
}

26
src/utils/toJSON.ts Normal file
View File

@@ -0,0 +1,26 @@
export const toJSON = (str: string): any => {
try {
// Remove curly braces and split by comma
const pairs = str.trim().slice(1, -1).split(",");
// Convert to object with explicit type
const obj: Record<string, any> = {};
pairs.forEach((pair) => {
const [key, value] = pair
.trim()
.split(":")
.map((s) => s.trim());
if (!key || value === undefined) {
throw new Error("Invalid key-value pair format");
}
obj[key] = isNaN(Number(value)) ? value : Number(value);
});
return JSON.parse(JSON.stringify(obj));
} catch (error) {
throw new Error(`Failed to parse string to JSON: ${error}`);
}
};