import { describe, it, expect, vi } from "vitest"; import { Trader } from "../trader"; import type { AnalystReport, DebateRound } from "../../types/agents"; const mockReports: AnalystReport[] = [ { analyst: "fundamentals", report: "Strong earnings growth", signal: { agent: "fundamentals", signal: "bullish", confidence: 0.8, reasoning: "Revenue up 20%", timestamp: "2024-01-01", }, }, ]; const mockDebates: DebateRound[] = [ { bullishView: "Strong fundamentals", bearishView: "Market volatility", researcher: "bullish", }, ]; describe("Trader executionPlan parsing", () => { it("includes executionPlan for buy decisions", async () => { const mockBuyClient = { createChatCompletion: vi.fn().mockResolvedValue({ choices: [{ message: { content: JSON.stringify({ action: "buy", confidence: 0.8, reasoning: "Enter position", executionPlan: { amount: 10, stopLoss: 95, riskManagement: { maxLossPercent: 1 }, takeProfit: 110 } }) } }] }), }; const trader = new Trader(mockBuyClient as any); const decision = await trader.decide("AAPL", mockReports, mockDebates); expect(decision.action).toBe("buy"); expect(decision.executionPlan).toBeDefined(); expect(decision.executionPlan?.amount).toBe(10); expect(decision.executionPlan?.stopLoss).toBe(95); }); it("parses stopLoss from malformed executionPlan text (fallback)", async () => { const malformed = 'Model reply: "action": "sell", "executionPlan": { amount: 7, takeProfit: 120, stopLoss: 115, riskManagement: { maxLossPercent: 2 } } and commentary.'; const mockMalformedClient = { createChatCompletion: vi.fn().mockResolvedValue({ choices: [{ message: { content: malformed } }], }), }; const trader = new Trader(mockMalformedClient as any); const decision = await trader.decide("AAPL", mockReports, mockDebates); // action may be unspecified in this malformed reply; ensure executionPlan fields parsed when present expect(decision.executionPlan).toBeDefined(); expect(decision.executionPlan?.amount).toBe(7); expect(decision.executionPlan?.stopLoss).toBe(115); expect(decision.executionPlan?.takeProfit).toBe(120); expect(decision.executionPlan?.riskManagement?.maxLossPercent).toBe(2); }); });