"use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; import { z } from "zod"; import { cn } from "@/lib/utils"; import { Target, AlertCircle, Info, TrendingUp, TrendingDown, Bell, ExternalLink } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { ChainIcon } from "@/components/crypto/ChainIcon"; import { useState } from "react"; // Schema for trading suggestion tool arguments export const TradingSuggestionArgsSchema = z.object({ tokenSymbol: z.string(), tokenName: z.string().optional(), chain: z.string(), contractAddress: z.string().optional(), currentPrice: z.number(), entry: z.object({ min: z.number(), max: z.number(), reasoning: z.string(), }), targets: z.array(z.object({ level: z.number(), price: z.number(), percentGain: z.number(), confidence: z.number(), })), stopLoss: z.object({ price: z.number(), percentLoss: z.number(), reasoning: z.string(), }), riskReward: z.number(), overallConfidence: z.number(), reasoning: z.array(z.string()), invalidationConditions: z.array(z.string()), }); export type TradingSuggestionArgs = z.infer; // Schema for trading suggestion result export const TradingSuggestionResultSchema = z.object({ success: z.boolean(), message: z.string().optional(), alertsSet: z.boolean().optional(), }); export type TradingSuggestionResult = z.infer; const formatPrice = (price: number): string => { if (price < 0.00001) return `$${price.toExponential(2)}`; if (price < 0.01) return `$${price.toFixed(8)}`; if (price < 1) return `$${price.toFixed(6)}`; return `$${price.toFixed(4)}`; }; const getRiskRewardColor = (ratio: number) => { if (ratio >= 3) return "text-green-500"; if (ratio >= 2) return "text-yellow-500"; return "text-red-500"; }; const getRiskRewardLabel = (ratio: number) => { if (ratio >= 3) return "Excellent"; if (ratio >= 2) return "Good"; if (ratio >= 1.5) return "Fair"; return "Poor"; }; /** * TradingSuggestionToolUI - Displays AI-powered trading suggestions in chat * Used when AI responds to queries like "suggest entry for BONK" or "trading suggestion for SOL" */ export const TradingSuggestionToolUI = makeAssistantToolUI({ toolName: "trading_suggestion", render: ({ args, result, status }) => { const [showDetails, setShowDetails] = useState(false); const isLoading = status.type === "running"; const handleOpenDexScreener = () => { if (args.contractAddress) { window.open(`https://dexscreener.com/${args.chain}/${args.contractAddress}`, "_blank"); } }; return (
Trading Suggestion {isLoading && Analyzing...}
Confidence
{args.overallConfidence}%
{/* Token Header */}
{args.tokenSymbol} {args.tokenName && {args.tokenName}}
{formatPrice(args.currentPrice)}
{/* Entry Zone */}
Entry Zone
{formatPrice(args.entry.min)} - {formatPrice(args.entry.max)}

{args.entry.reasoning}

{/* Targets */}
Take Profit Targets
{args.targets.map((target) => (
🎯 T{target.level} {formatPrice(target.price)}
+{target.percentGain.toFixed(1)}% {target.confidence}%
))}
{/* Stop Loss */}
Stop Loss
{formatPrice(args.stopLoss.price)} {args.stopLoss.percentLoss.toFixed(1)}%

{args.stopLoss.reasoning}

{/* Risk/Reward */}
Risk/Reward Ratio
= 3 ? "default" : args.riskReward >= 2 ? "secondary" : "destructive"}> {getRiskRewardLabel(args.riskReward)} 1:{args.riskReward.toFixed(1)}
{/* Why? Section - Collapsible */}
{showDetails && (

Reasoning:

    {args.reasoning.map((reason, i) => (
  • {reason}
  • ))}

Invalidation:

    {args.invalidationConditions.map((condition, i) => (
  • {condition}
  • ))}
)}
{/* Action Buttons */}
); }, });