+ {/* Shadow/gradient overlay on left edge */}
+
{/* Header */}
@@ -852,6 +854,13 @@ function LLMControls({ node }: { node: Node }) {
[node.id, updateNodeData]
);
+ const handleMaxTokensChange = useCallback(
+ (e: React.ChangeEvent) => {
+ updateNodeData(node.id, { maxTokens: parseInt(e.target.value, 10) });
+ },
+ [node.id, updateNodeData]
+ );
+
const provider = nodeData.provider || "google";
const availableModels = LLM_MODELS[provider] || LLM_MODELS.google;
@@ -897,6 +906,21 @@ function LLMControls({ node }: { node: Node }) {
className="nodrag nopan w-full h-1 bg-neutral-700 rounded-lg appearance-none cursor-pointer accent-blue-500"
/>
+
+
+
+
+
);
}
diff --git a/src/components/nodes/LLMGenerateNode.tsx b/src/components/nodes/LLMGenerateNode.tsx
index 77758752..224a44e6 100644
--- a/src/components/nodes/LLMGenerateNode.tsx
+++ b/src/components/nodes/LLMGenerateNode.tsx
@@ -4,31 +4,7 @@ import { useCallback, useState } from "react";
import { Handle, Position, NodeProps, Node } from "@xyflow/react";
import { BaseNode } from "./BaseNode";
import { useWorkflowStore } from "@/store/workflowStore";
-import { LLMGenerateNodeData, LLMProvider, LLMModelType } from "@/types";
-
-const PROVIDERS: { value: LLMProvider; label: string }[] = [
- { value: "google", label: "Google" },
- { value: "openai", label: "OpenAI" },
- { value: "anthropic", label: "Anthropic" },
-];
-
-const MODELS: Record
= {
- google: [
- { value: "gemini-3-flash-preview", label: "Gemini 3 Flash" },
- { value: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
- { value: "gemini-3-pro-preview", label: "Gemini 3.0 Pro" },
- { value: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro" },
- ],
- openai: [
- { value: "gpt-4.1-mini", label: "GPT-4.1 Mini" },
- { value: "gpt-4.1-nano", label: "GPT-4.1 Nano" },
- ],
- anthropic: [
- { value: "claude-sonnet-4.5", label: "Claude Sonnet 4.5" },
- { value: "claude-haiku-4.5", label: "Claude Haiku 4.5" },
- { value: "claude-opus-4.6", label: "Claude Opus 4.6" },
- ],
-};
+import { LLMGenerateNodeData } from "@/types";
type LLMGenerateNodeType = Node;
@@ -36,46 +12,6 @@ export function LLMGenerateNode({ id, data, selected }: NodeProps state.updateNodeData);
- const handleProviderChange = useCallback(
- (e: React.ChangeEvent) => {
- const newProvider = e.target.value as LLMProvider;
- const firstModelForProvider = MODELS[newProvider][0].value;
- const updates: Partial = {
- provider: newProvider,
- model: firstModelForProvider,
- };
- // Anthropic limits temperature to 0-1
- if (newProvider === "anthropic" && nodeData.temperature > 1) {
- updates.temperature = 1;
- }
- updateNodeData(id, updates);
- },
- [id, updateNodeData, nodeData.temperature]
- );
-
- const handleModelChange = useCallback(
- (e: React.ChangeEvent) => {
- updateNodeData(id, { model: e.target.value as LLMModelType });
- },
- [id, updateNodeData]
- );
-
- const handleTemperatureChange = useCallback(
- (e: React.ChangeEvent) => {
- updateNodeData(id, { temperature: parseFloat(e.target.value) });
- },
- [id, updateNodeData]
- );
-
- const handleMaxTokensChange = useCallback(
- (e: React.ChangeEvent) => {
- updateNodeData(id, { maxTokens: parseInt(e.target.value, 10) });
- },
- [id, updateNodeData]
- );
-
- const [showParams, setShowParams] = useState(false);
-
const regenerateNode = useWorkflowStore((state) => state.regenerateNode);
const isRunning = useWorkflowStore((state) => state.isRunning);
@@ -101,18 +37,13 @@ export function LLMGenerateNode({ id, data, selected }: NodeProps m.value === nodeData.model)
- ? nodeData.model
- : availableModels[0].value;
-
return (
{/* Image input - optional */}
-
- {/* Output preview area */}
-
- {nodeData.status === "loading" ? (
-
- ) : nodeData.status === "error" ? (
-
- {nodeData.error || "Failed"}
-
- ) : nodeData.outputText ? (
- <>
-
- {nodeData.outputText}
-
-
-
-
-
-
- >
- ) : (
-
-
- Run to generate
-
-
- )}
-
-
- {/* Provider selector */}
-
-
- {/* Model selector */}
-
-
- {/* Collapsible parameters section */}
-
-