From 6ccf7b68cbe0d38ee098df9fb441d57cc356ed3c Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 03:49:52 +0000
Subject: [PATCH] feat: Add custom AI prompt functionality
This commit introduces a new feature allowing users to customize the AI's system prompt.
- A `SettingsModal` component has been created to provide a UI for editing and saving the custom prompt.
- A "Settings" button has been added to the application header to open the modal.
- The custom prompt is saved to `localStorage` to persist between sessions.
- The `createAIChildren` function has been updated to use the custom prompt when making API calls.
- The default prompt is retained as a fallback.
---
src/App.jsx | 76 +++++++++++++++++++++++++++++--------
src/SettingsModal.jsx | 87 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 16 deletions(-)
create mode 100644 src/SettingsModal.jsx
diff --git a/src/App.jsx b/src/App.jsx
index 5f3df15..ba1ac52 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,5 +1,6 @@
// 📦 Imports
-import React, { useState, useRef } from 'react';
+import React, { useState, useRef, useEffect } from 'react';
+import SettingsModal from './SettingsModal';
import ReactFlow, {
Background,
Controls,
@@ -27,7 +28,7 @@ const getColor = (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 +38,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 +87,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) {
@@ -115,6 +106,37 @@ export default function App() {
const [loading, setLoading] = useState(false);
const stopGenerationRef = useRef(false);
const reactFlowWrapper = useRef(null);
+ const [isSettingsModalOpen, setSettingsModalOpen] = useState(false);
+
+ 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.`;
+
+ const [systemPrompt, setSystemPrompt] = useState(defaultSystemPrompt);
+ const [tempSystemPrompt, setTempSystemPrompt] = useState(systemPrompt);
+
+ useEffect(() => {
+ const savedPrompt = localStorage.getItem('customSystemPrompt');
+ if (savedPrompt) {
+ setSystemPrompt(savedPrompt);
+ setTempSystemPrompt(savedPrompt);
+ }
+ }, []);
+
+ const handleSaveSystemPrompt = (newPrompt) => {
+ setSystemPrompt(newPrompt);
+ localStorage.setItem('customSystemPrompt', newPrompt);
+ setSettingsModalOpen(false);
+ };
+
const handleExport = () => {
if (reactFlowWrapper.current) {
@@ -150,7 +172,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 +186,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 +268,31 @@ export default function App() {
>
Export as PNG
+
+ setSettingsModalOpen(false)}
+ systemPrompt={tempSystemPrompt}
+ setSystemPrompt={setTempSystemPrompt}
+ onSave={handleSaveSystemPrompt}
+ />
+
{/* 🧠ReactFlow Canvas */}