import { tool } from 'ai'; import { z } from "zod"; import { queryBirdeye } from "./client.js"; const searchTokens = async ({ keyword, verifyToken, offset = 0, limit = 20 }) => { limit = Math.min(limit, 20); const params = { keyword, chain: "solana", target: "token", sort_by: "liquidity", sort_type: "desc", offset, limit }; if (verifyToken !== undefined) { params.verify_token = verifyToken.toString(); } const response = await queryBirdeye("defi/v3/search", params); const filteredTokens = response.items .filter(item => item.type === "token") .flatMap(item => item.result .filter(token => token.network === "solana") .map(({ decimals, ...rest }) => rest) ); return filteredTokens.length > 0 ? filteredTokens.slice(0, 20) : []; }; export const getSearchTokensTool = (userId, chatId,responseId, dataStream) => tool({ description: "Search for tokens using name or ticker with options to filter verified tokens and paginate. When a user asks about ticker on-chain data and doesn't provide the contract address, look up verified tokens, unless the user says it's a new token.", parameters: z.object({ keyword: z.string().describe("name or ticker to search for tokens"), isVerified: z .boolean() .optional() .describe("Optional filter to return only verified tokens"), offset: z .number() .optional() .describe("Offset for pagination"), limit: z .number() .optional() .describe("Limit for the number of results (max: 20)") }), execute: async ({ keyword, isVerified, offset, limit }) => { try { console.log(`${userId} ${chatId} called searchTokens with keyword: ${keyword} | isVerified: ${isVerified} | offset: ${offset} | limit: ${limit}`); const verifyToken = isVerified !== undefined ? isVerified : true; const tokens = await searchTokens({ keyword, verifyToken, offset, limit }); if (tokens) { tokens.forEach(token => { dataStream.writeMessageAnnotation({ id: responseId, tool_type: 'chart', content: token.address.toString(), }); }); } return tokens; } catch (error) { console.error(`Error occurred while searching for tokens: ${error.message}`); return 'Failed to search for tokens.'; } }, });