import { OpenRouterClient } from "../lib/openrouter"; import type { AnalystReport, AgentSignal, SignalType } from "../types/agents"; export interface SentimentConfig { model?: string; } export interface SentimentData { headlines: string[]; source?: "news" | "social" | "stocktwits"; } export class SentimentAnalyst { private client: OpenRouterClient; private model: string; constructor(client: OpenRouterClient, config?: SentimentConfig) { this.client = client; this.model = config?.model ?? "openai/gpt-oss-120b:free"; } getModel(): string { return this.model; } async analyze(ticker: string, data: SentimentData): Promise { const messages = [ { role: "system" as const, content: "You are a sentiment analyst. Analyze the headlines for the given ticker and provide a bullish, bearish, or neutral signal with reasoning. Respond in JSON format with 'signal', 'confidence', and 'reasoning' fields.", }, { role: "user" as const, content: `Analyze ${ticker} sentiment from ${data.source ?? "news"}:\n${data.headlines.join("\n")}`, }, ]; const response = await this.client.createChatCompletion( messages, this.model ); const parsedResponse = response as { choices?: Array<{ message?: { content?: string } }>; }; const content = parsedResponse.choices?.[0]?.message?.content ?? ""; let signal: SignalType = "neutral"; let confidence = 0.5; let reasoning = content; try { const parsed = JSON.parse(content); if ( parsed.signal === "bullish" || parsed.signal === "bearish" || parsed.signal === "neutral" ) { signal = parsed.signal; confidence = parsed.confidence ?? 0.5; reasoning = parsed.reasoning ?? content; } } catch { const lowerContent = content.toLowerCase(); if (lowerContent.includes("bullish")) signal = "bullish"; else if (lowerContent.includes("bearish")) signal = "bearish"; } const agentSignal: AgentSignal = { agent: "sentiment", signal, confidence, reasoning, timestamp: new Date().toISOString(), }; return { analyst: "sentiment", report: content, signal: agentSignal, }; } }