diff --git a/src/components/nodes/LLMGenerateNode.tsx b/src/components/nodes/LLMGenerateNode.tsx index 05697b19..e22e2979 100644 --- a/src/components/nodes/LLMGenerateNode.tsx +++ b/src/components/nodes/LLMGenerateNode.tsx @@ -7,6 +7,7 @@ import { useWorkflowStore } from "@/store/workflowStore"; import { LLMGenerateNodeData, LLMProvider, LLMModelType } from "@/types"; import { useInlineParameters } from "@/hooks/useInlineParameters"; import { InlineParameterPanel } from "./InlineParameterPanel"; +import { SettingsTabBar } from "./SettingsTabBar"; // LLM providers and models const LLM_PROVIDERS: { value: LLMProvider; label: string }[] = [ @@ -54,6 +55,7 @@ export function LLMGenerateNode({ id, data, selected }: NodeProps("primary"); const handleCopyOutput = useCallback(async () => { if (nodeData.outputText) { @@ -129,68 +131,131 @@ export function LLMGenerateNode({ id, data, selected }: NodeProps - {/* LLM-specific controls */} -
- {/* Provider */} -
- - -
+ {/* Tab bar for primary/fallback settings */} + {nodeData.fallbackModel && ( + + )} - {/* Model */} -
- - -
+ {/* Primary tab: LLM-specific controls */} + {settingsTab === "primary" && ( +
+ {/* Provider */} +
+ + +
- {/* Temperature */} -
- - -
+ {/* Model */} +
+ + +
- {/* Max Tokens */} -
- - + {/* Temperature */} +
+ + +
+ + {/* Max Tokens */} +
+ + +
-
+ )} + + {/* Fallback tab: temperature + maxTokens for fallback model */} + {settingsTab === "fallback" && nodeData.fallbackModel && (() => { + const fbParams = nodeData.fallbackParameters || {}; + const fbTemp = (fbParams.temperature as number | undefined) ?? 0.7; + const fbMaxTokens = (fbParams.maxTokens as number | undefined) ?? 2048; + const fbProvider = nodeData.fallbackModel!.provider; + const isAnthropicFb = fbProvider === "anthropic"; + + return ( +
+ {/* Read-only model display */} +
+ + {nodeData.fallbackModel!.displayName} +
+ + {/* Temperature */} +
+ + updateNodeData(id, { fallbackParameters: { ...fbParams, temperature: parseFloat(e.target.value) } })} + className="nodrag nopan w-full h-1 bg-neutral-700 rounded-lg appearance-none cursor-pointer accent-blue-500" + /> +
+ + {/* Max Tokens */} +
+ + updateNodeData(id, { fallbackParameters: { ...fbParams, maxTokens: parseInt(e.target.value, 10) } })} + className="nodrag nopan w-full h-1 bg-neutral-700 rounded-lg appearance-none cursor-pointer accent-blue-500" + /> +
+
+ ); + })()} ) : undefined} > diff --git a/src/store/execution/llmGenerateExecutor.ts b/src/store/execution/llmGenerateExecutor.ts index f52b2a71..3d8e7fa7 100644 --- a/src/store/execution/llmGenerateExecutor.ts +++ b/src/store/execution/llmGenerateExecutor.ts @@ -77,11 +77,14 @@ export async function executeLlmGenerate( error: null, }); - const runOnce = async (modelToUse: SelectedModel): Promise => { + const runOnce = async (modelToUse: SelectedModel, parametersOverride?: Record): Promise => { const llmProvider = providerTypeToLlmProvider(modelToUse.provider); const llmModel = modelToUse.modelId as LLMModelType; const headers = buildLlmHeaders(llmProvider, providerSettings); + const temperature = (parametersOverride?.temperature as number | undefined) ?? nodeData.temperature; + const maxTokens = (parametersOverride?.maxTokens as number | undefined) ?? nodeData.maxTokens; + try { const response = await fetch("/api/llm", { method: "POST", @@ -91,8 +94,8 @@ export async function executeLlmGenerate( ...(images.length > 0 && { images }), provider: llmProvider, model: llmModel, - temperature: nodeData.temperature, - maxTokens: nodeData.maxTokens, + temperature, + maxTokens, }), ...(signal ? { signal } : {}), }); @@ -165,7 +168,9 @@ export async function executeLlmGenerate( nodeId: node.id, primary: primaryModel, fallback: nodeData.fallbackModel, + fallbackParameters: nodeData.fallbackParameters, updateNodeData, runOnce, + clearOutput: { outputText: null }, }); } diff --git a/src/types/nodes.ts b/src/types/nodes.ts index 49cc4b73..901dafae 100644 --- a/src/types/nodes.ts +++ b/src/types/nodes.ts @@ -305,6 +305,7 @@ export interface LLMGenerateNodeData extends BaseNodeData { model: LLMModelType; temperature: number; maxTokens: number; + fallbackParameters?: Record; // Parameters for fallback model (temperature, maxTokens) parametersExpanded?: boolean; // Collapse state for inline parameter display _settingsPanelHeight?: number; // Measured settings panel height for reload correction status: NodeStatus;