From 2ab55060f3c1fd058d7ae8b07e9f3ef7c1117ff4 Mon Sep 17 00:00:00 2001 From: Henry Winkel Date: Sat, 16 May 2026 21:37:27 +0200 Subject: [PATCH] feat: wire TradingGraph to use settings for model, temperature, and risk config --- app/lib/execution.ts | 4 ++-- app/lib/openrouter.ts | 5 ++++- app/lib/queue.ts | 14 ++++++-------- app/lib/tradingConfig.server.ts | 34 +++++++++++++++++++++++++++++++++ app/routes/api/analyze.ts | 9 ++++----- 5 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 app/lib/tradingConfig.server.ts diff --git a/app/lib/execution.ts b/app/lib/execution.ts index ca416fa..b657300 100644 --- a/app/lib/execution.ts +++ b/app/lib/execution.ts @@ -89,13 +89,13 @@ export function enrichExecutionPlan(decision: TradingDecision, input: any): Trad } // Optional LLM verification step: review computed executionPlan and suggest adjustments -export async function verifyExecutionPlanWithLLM(decision: TradingDecision, input: any): Promise { +export async function verifyExecutionPlanWithLLM(decision: TradingDecision, input: any, model?: string): Promise { try { const apiKey = process.env.OPENROUTER_API_KEY; if (!apiKey) return decision; const { OpenRouterClient } = await import("./openrouter"); - const client = new OpenRouterClient(apiKey); + const client = new OpenRouterClient(apiKey, { defaultModel: model }); const plan = decision.executionPlan || {}; const prices: number[] = input?.technicalData?.prices || []; diff --git a/app/lib/openrouter.ts b/app/lib/openrouter.ts index ba0da4b..369f014 100644 --- a/app/lib/openrouter.ts +++ b/app/lib/openrouter.ts @@ -36,7 +36,8 @@ export class OpenRouterClient { async createChatCompletion( messages: Message[], - model?: string + model?: string, + options?: { temperature?: number; max_tokens?: number } ): Promise { const response = await fetch(`${this.baseURL}/chat/completions`, { method: "POST", @@ -49,6 +50,8 @@ export class OpenRouterClient { body: JSON.stringify({ model: model ?? this.defaultModel, messages, + ...(options?.temperature != null && { temperature: options.temperature }), + ...(options?.max_tokens != null && { max_tokens: options.max_tokens }), }), }); diff --git a/app/lib/queue.ts b/app/lib/queue.ts index 1d53ba8..eb722d7 100644 --- a/app/lib/queue.ts +++ b/app/lib/queue.ts @@ -2,8 +2,7 @@ import pkg from "bullmq"; const { Queue, Worker } = pkg as any; import IORedis from "ioredis"; import { fetchAccount, fetchRecentCloses } from "./alpacaClient"; -import { OpenRouterClient } from "./openrouter"; -import { TradingGraph } from "../agents/tradingGraph"; +import { buildTradingGraph, getTradingConfig } from "./tradingConfig.server"; import { db } from "./db.server"; const REDIS_URL = process.env.REDIS_URL; @@ -41,8 +40,8 @@ if (REDIS_URL) { return mockDecision; } - const client = new OpenRouterClient(apiKey); - const graph = new TradingGraph(client); + const { graph, config } = await buildTradingGraph(apiKey); + console.log("[queue] Trading config:", config); // Fetch latest Alpaca account and prices; abort job if unavailable so work runs on fresh data try { const account = await fetchAccount(); @@ -64,7 +63,7 @@ if (REDIS_URL) { decision = enrichExecutionPlan(decision, input); if (process.env.OPENROUTER_API_KEY) { try { - decision = await verifyExecutionPlanWithLLM(decision, input); + decision = await verifyExecutionPlanWithLLM(decision, input, config.model); } catch (e) { console.warn("[queue] LLM verification failed:", e); } @@ -191,8 +190,7 @@ if (REDIS_URL) { }); continue; } - const client = new OpenRouterClient(process.env.OPENROUTER_API_KEY as string); - const graph = new TradingGraph(client); + const { graph, config } = await buildTradingGraph(process.env.OPENROUTER_API_KEY as string); // Fetch latest Alpaca account and prices; abort job if unavailable so work runs on fresh data try { const account = await fetchAccount(); @@ -215,7 +213,7 @@ if (REDIS_URL) { decision = enrichExecutionPlan(decision, job.input); if (process.env.OPENROUTER_API_KEY) { try { - decision = await verifyExecutionPlanWithLLM(decision, job.input); + decision = await verifyExecutionPlanWithLLM(decision, job.input, config.model); } catch (e) { console.warn("[inproc queue] LLM verification failed:", e); } diff --git a/app/lib/tradingConfig.server.ts b/app/lib/tradingConfig.server.ts new file mode 100644 index 0000000..d9df6c2 --- /dev/null +++ b/app/lib/tradingConfig.server.ts @@ -0,0 +1,34 @@ +import { settingsService } from "./settings.server"; +import { OpenRouterClient } from "./openrouter"; +import { TradingGraph } from "../agents/tradingGraph"; + +export interface TradingConfig { + model: string; + temperature: number; + maxDebateRounds: number; +} + +const DEFAULT_CONFIG: TradingConfig = { + model: "openai/gpt-oss-120b:free", + temperature: 0.7, + maxDebateRounds: 3, +}; + +export async function getTradingConfig(): Promise { + try { + await settingsService.init(); + const model = (await settingsService.get("llm.model")) ?? DEFAULT_CONFIG.model; + const temperature = (await settingsService.get("llm.temperature")) ?? DEFAULT_CONFIG.temperature; + const maxDebateRounds = (await settingsService.get("llm.maxDebateRounds")) ?? DEFAULT_CONFIG.maxDebateRounds; + return { model, temperature, maxDebateRounds }; + } catch { + return DEFAULT_CONFIG; + } +} + +export async function buildTradingGraph(apiKey: string): Promise<{ graph: TradingGraph; client: OpenRouterClient; config: TradingConfig }> { + const config = await getTradingConfig(); + const client = new OpenRouterClient(apiKey, { defaultModel: config.model }); + const graph = new TradingGraph(client, config.model); + return { graph, client, config }; +} diff --git a/app/routes/api/analyze.ts b/app/routes/api/analyze.ts index 6f73ad4..1c8f651 100644 --- a/app/routes/api/analyze.ts +++ b/app/routes/api/analyze.ts @@ -17,8 +17,7 @@ export async function action({ request }: { request: Request }) { } // Load server-only modules dynamically to prevent them from being included in client bundles - const { OpenRouterClient } = await import("../../lib/openrouter"); - const { TradingGraph } = await import("../../agents/tradingGraph"); + const { buildTradingGraph } = await import("../../lib/tradingConfig.server"); const { db } = await import("../../lib/db.server"); const { fetchAccount, fetchRecentCloses, fetchBars } = await import("../../lib/alpacaClient"); @@ -59,8 +58,8 @@ export async function action({ request }: { request: Request }) { return Response.json(mockDecision); } - const client = new OpenRouterClient(apiKey); - const graph = new TradingGraph(client); + const { graph, config } = await buildTradingGraph(apiKey); + console.log("[analyze] Trading config:", config); // Fetch latest Alpaca account and recent prices; abort if unavailable let account: any = undefined; @@ -124,7 +123,7 @@ export async function action({ request }: { request: Request }) { // Optionally ask LLM to verify/adjust the computed plan if API key is present if (process.env.OPENROUTER_API_KEY) { try { - decision = await verifyExecutionPlanWithLLM(decision, input); + decision = await verifyExecutionPlanWithLLM(decision, input, config.model); } catch (e) { console.warn("LLM verification failed:", e); }