From 4746c9d09e1f269b3dced3748d69e1fb570f782b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 03:46:11 +0000 Subject: [PATCH] feat: Implement custom system prompt feature Adds a settings modal to allow users to define and save a custom system prompt for the AI. The prompt is stored in localStorage and used in AI generation requests. This enhances the application's flexibility by giving users more control over the AI's behavior. --- src/App.jsx | 64 ++++++++++++++++++++++++++--------- src/SettingsModal.jsx | 78 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 src/SettingsModal.jsx diff --git a/src/App.jsx b/src/App.jsx index 5f3df15..1151848 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,6 @@ // 📦 Imports import React, { useState, useRef } from 'react'; +import SettingsModal from './SettingsModal'; import ReactFlow, { Background, Controls, @@ -26,8 +27,20 @@ const getColor = (type) => { } }; +const defaultSystemPrompt = `You are an expert in cause-and-effect analysis. + +Given a news headline or event, break it down into a chain of consequences, like a domino effect. + +Each node must: +- Be short (max 15 words) +- Represent one specific consequence +- Be categorized as either: 'positive', 'neutral', or 'negative' +- Be logically linked to the prompt + +Return only 3 outputs: one of each type.`; + // 🤖 AI Logic with Domino Effect Thinking (Updated: Using Puter AI API) -const createAIChildren = async (text, parentId, setNodes, setEdges, stopGenerationRef) => { +const createAIChildren = async (text, parentId, setNodes, setEdges, stopGenerationRef, systemPrompt) => { try { if (stopGenerationRef.current) return; const res = await axios.post( @@ -37,17 +50,7 @@ const createAIChildren = async (text, parentId, setNodes, setEdges, stopGenerati messages: [ { role: 'system', - content: `You are an expert in cause-and-effect analysis. - -Given a news headline or event, break it down into a chain of consequences, like a domino effect. - -Each node must: -- Be short (max 15 words) -- Represent one specific consequence -- Be categorized as either: 'positive', 'neutral', or 'negative' -- Be logically linked to the prompt - -Return only 3 outputs: one of each type.` + content: systemPrompt }, { role: 'user', content: text } ] @@ -96,7 +99,7 @@ Return only 3 outputs: one of each type.` // Recursively expand each child one level deep for (const n of newNodes) { if (stopGenerationRef.current) break; - await createAIChildren(n.data.label, n.id, setNodes, setEdges, stopGenerationRef); + await createAIChildren(n.data.label, n.id, setNodes, setEdges, stopGenerationRef, systemPrompt); } } catch (err) { @@ -113,6 +116,10 @@ export default function App() { const [edges, setEdges] = useState(initialEdges); const [prompt, setPrompt] = useState(''); const [loading, setLoading] = useState(false); + const [isSettingsOpen, setIsSettingsOpen] = useState(false); + const [systemPrompt, setSystemPrompt] = useState( + localStorage.getItem('customSystemPrompt') || defaultSystemPrompt + ); const stopGenerationRef = useRef(false); const reactFlowWrapper = useRef(null); @@ -126,6 +133,11 @@ export default function App() { } }; + const handleSaveSettings = () => { + localStorage.setItem('customSystemPrompt', systemPrompt); + setIsSettingsOpen(false); + }; + const handleSubmit = async () => { if (!prompt.trim()) return; setLoading(true); @@ -150,7 +162,7 @@ export default function App() { setNodes([rootNode]); setEdges([]); - await createAIChildren(prompt, rootId, setNodes, setEdges, stopGenerationRef); + await createAIChildren(prompt, rootId, setNodes, setEdges, stopGenerationRef, systemPrompt); setPrompt(''); setLoading(false); @@ -164,7 +176,7 @@ export default function App() { const onNodeClick = async (_event, node) => { stopGenerationRef.current = false; setLoading(true); - await createAIChildren(node.data.label, node.id, setNodes, setEdges, stopGenerationRef); + await createAIChildren(node.data.label, node.id, setNodes, setEdges, stopGenerationRef, systemPrompt); setLoading(false); }; @@ -246,9 +258,31 @@ export default function App() { > Export as PNG + setIsSettingsOpen(true)} + style={{ + padding: '10px 20px', + backgroundColor: '#666', + color: 'white', + border: 'none', + borderRadius: '8px', + fontWeight: 'bold', + cursor: 'pointer', + }} + > + Settings + + setIsSettingsOpen(false)} + systemPrompt={systemPrompt} + setSystemPrompt={setSystemPrompt} + onSave={handleSaveSettings} + /> + {/* 🧠 ReactFlow Canvas */} { + if (!isOpen) return null; + + return ( + + + Custom System Prompt + + Define the AI's persona and instructions here. + + setSystemPrompt(e.target.value)} + style={{ + width: '100%', + height: '200px', + borderRadius: '4px', + border: '1px solid #555', + backgroundColor: '#222', + color: '#fff', + padding: '10px', + fontSize: '1rem', + }} + /> + + + Cancel + + + Save + + + + + ); +}; + +export default SettingsModal;
+ Define the AI's persona and instructions here. +