summaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'frontend')
-rw-r--r--frontend/package-lock.json294
-rw-r--r--frontend/package.json1
-rw-r--r--frontend/src/components/LeftSidebar.tsx68
-rw-r--r--frontend/src/components/Sidebar.tsx25
4 files changed, 381 insertions, 7 deletions
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 8cf5871..7a3c457 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -13,6 +13,7 @@
"react-dom": "^19.2.0",
"react-markdown": "^10.1.0",
"reactflow": "^11.11.4",
+ "remark-gfm": "^4.0.1",
"zustand": "^5.0.9"
},
"devDependencies": {
@@ -3665,6 +3666,44 @@
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
+ "node_modules/markdown-table": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
+ "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
+ "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "escape-string-regexp": "^5.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/mdast-util-from-markdown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
@@ -3688,6 +3727,107 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/mdast-util-gfm": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
+ "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-gfm-autolink-literal": "^2.0.0",
+ "mdast-util-gfm-footnote": "^2.0.0",
+ "mdast-util-gfm-strikethrough": "^2.0.0",
+ "mdast-util-gfm-table": "^2.0.0",
+ "mdast-util-gfm-task-list-item": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
+ "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-find-and-replace": "^3.0.0",
+ "micromark-util-character": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
+ "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
+ "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "markdown-table": "^3.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-task-list-item": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
+ "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/mdast-util-mdx-expression": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
@@ -3887,6 +4027,127 @@
"micromark-util-types": "^2.0.0"
}
},
+ "node_modules/micromark-extension-gfm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
+ "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-extension-gfm-autolink-literal": "^2.0.0",
+ "micromark-extension-gfm-footnote": "^2.0.0",
+ "micromark-extension-gfm-strikethrough": "^2.0.0",
+ "micromark-extension-gfm-table": "^2.0.0",
+ "micromark-extension-gfm-tagfilter": "^2.0.0",
+ "micromark-extension-gfm-task-list-item": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
+ "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
+ "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
+ "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
+ "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
+ "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/micromark-factory-destination": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
@@ -4823,6 +5084,24 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/remark-gfm": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+ "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-gfm": "^3.0.0",
+ "micromark-extension-gfm": "^3.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-stringify": "^11.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/remark-parse": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
@@ -4854,6 +5133,21 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/remark-stringify": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
+ "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 4169f9a..94cef9c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,6 +15,7 @@
"react-dom": "^19.2.0",
"react-markdown": "^10.1.0",
"reactflow": "^11.11.4",
+ "remark-gfm": "^4.0.1",
"zustand": "^5.0.9"
},
"devDependencies": {
diff --git a/frontend/src/components/LeftSidebar.tsx b/frontend/src/components/LeftSidebar.tsx
index 6806ca3..5c464bb 100644
--- a/frontend/src/components/LeftSidebar.tsx
+++ b/frontend/src/components/LeftSidebar.tsx
@@ -62,8 +62,12 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
const [openaiApiKey, setOpenaiApiKey] = useState('');
const [geminiApiKey, setGeminiApiKey] = useState('');
const [showGuide, setShowGuide] = useState(false);
+ const [claudeApiKey, setClaudeApiKey] = useState('');
+ const [openrouterApiKey, setOpenrouterApiKey] = useState('');
const [showOpenaiKey, setShowOpenaiKey] = useState(false);
const [showGeminiKey, setShowGeminiKey] = useState(false);
+ const [showClaudeKey, setShowClaudeKey] = useState(false);
+ const [showOpenrouterKey, setShowOpenrouterKey] = useState(false);
const [savingKeys, setSavingKeys] = useState(false);
const [keysMessage, setKeysMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
const { getAuthHeader } = useAuthStore();
@@ -86,6 +90,8 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
.then(data => {
setOpenaiApiKey(data.openai_api_key || '');
setGeminiApiKey(data.gemini_api_key || '');
+ setClaudeApiKey(data.claude_api_key || '');
+ setOpenrouterApiKey(data.openrouter_api_key || '');
})
.catch(() => {});
}
@@ -101,6 +107,8 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
body: JSON.stringify({
openai_api_key: openaiApiKey.includes('*') ? undefined : openaiApiKey,
gemini_api_key: geminiApiKey.includes('*') ? undefined : geminiApiKey,
+ claude_api_key: claudeApiKey.includes('*') ? undefined : claudeApiKey,
+ openrouter_api_key: openrouterApiKey.includes('*') ? undefined : openrouterApiKey,
}),
});
if (res.ok) {
@@ -111,6 +119,8 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
}).then(r => r.json());
setOpenaiApiKey(data.openai_api_key || '');
setGeminiApiKey(data.gemini_api_key || '');
+ setClaudeApiKey(data.claude_api_key || '');
+ setOpenrouterApiKey(data.openrouter_api_key || '');
} else {
setKeysMessage({ type: 'error', text: 'Failed to save API keys' });
}
@@ -628,8 +638,8 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
onChange={e => setGeminiApiKey(e.target.value)}
placeholder="AI..."
className={`w-full px-3 py-2 pr-10 rounded-lg text-sm ${
- isDark
- ? 'bg-gray-700 border-gray-600 text-white placeholder-gray-500'
+ isDark
+ ? 'bg-gray-700 border-gray-600 text-white placeholder-gray-500'
: 'bg-white border-gray-300 text-gray-900 placeholder-gray-400'
} border focus:outline-none focus:ring-2 focus:ring-blue-500`}
/>
@@ -643,6 +653,60 @@ const LeftSidebar: React.FC<LeftSidebarProps> = ({ isOpen, onToggle }) => {
</div>
</div>
+ {/* Claude API Key */}
+ <div>
+ <label className={`block text-xs mb-1 ${isDark ? 'text-gray-400' : 'text-gray-600'}`}>
+ Claude API Key
+ </label>
+ <div className="relative">
+ <input
+ type={showClaudeKey ? 'text' : 'password'}
+ value={claudeApiKey}
+ onChange={e => setClaudeApiKey(e.target.value)}
+ placeholder="sk-ant-..."
+ className={`w-full px-3 py-2 pr-10 rounded-lg text-sm ${
+ isDark
+ ? 'bg-gray-700 border-gray-600 text-white placeholder-gray-500'
+ : 'bg-white border-gray-300 text-gray-900 placeholder-gray-400'
+ } border focus:outline-none focus:ring-2 focus:ring-blue-500`}
+ />
+ <button
+ type="button"
+ onClick={() => setShowClaudeKey(!showClaudeKey)}
+ className={`absolute right-2 top-1/2 -translate-y-1/2 p-1 ${isDark ? 'text-gray-400' : 'text-gray-500'}`}
+ >
+ {showClaudeKey ? <EyeOff size={16} /> : <Eye size={16} />}
+ </button>
+ </div>
+ </div>
+
+ {/* OpenRouter API Key (Fallback) */}
+ <div>
+ <label className={`block text-xs mb-1 ${isDark ? 'text-gray-400' : 'text-gray-600'}`}>
+ OpenRouter API Key <span className={`text-[10px] ${isDark ? 'text-gray-500' : 'text-gray-400'}`}>(fallback)</span>
+ </label>
+ <div className="relative">
+ <input
+ type={showOpenrouterKey ? 'text' : 'password'}
+ value={openrouterApiKey}
+ onChange={e => setOpenrouterApiKey(e.target.value)}
+ placeholder="sk-or-v1-..."
+ className={`w-full px-3 py-2 pr-10 rounded-lg text-sm ${
+ isDark
+ ? 'bg-gray-700 border-gray-600 text-white placeholder-gray-500'
+ : 'bg-white border-gray-300 text-gray-900 placeholder-gray-400'
+ } border focus:outline-none focus:ring-2 focus:ring-blue-500`}
+ />
+ <button
+ type="button"
+ onClick={() => setShowOpenrouterKey(!showOpenrouterKey)}
+ className={`absolute right-2 top-1/2 -translate-y-1/2 p-1 ${isDark ? 'text-gray-400' : 'text-gray-500'}`}
+ >
+ {showOpenrouterKey ? <EyeOff size={16} /> : <Eye size={16} />}
+ </button>
+ </div>
+ </div>
+
{/* Save Button */}
<button
onClick={handleSaveApiKeys}
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index 5141081..78d2475 100644
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -5,6 +5,7 @@ import { useAuthStore } from '../store/authStore';
import type { NodeData, Trace, Message, MergedTrace, MergeStrategy } from '../store/flowStore';
import type { Edge } from 'reactflow';
import ReactMarkdown from 'react-markdown';
+import remarkGfm from 'remark-gfm';
import { Play, Settings, Info, ChevronLeft, ChevronRight, Maximize2, Edit3, X, Check, FileText, MessageCircle, Send, GripVertical, GitMerge, Trash2, AlertCircle, Loader2, Navigation, Upload, Search, Link } from 'lucide-react';
interface SidebarProps {
@@ -312,7 +313,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
scopes,
merge_strategy: selectedNode.data.mergeStrategy || 'smart',
config: {
- provider: selectedNode.data.model.includes('gpt') || selectedNode.data.model === 'o3' ? 'openai' : 'google',
+ provider: selectedNode.data.model.includes('claude') ? 'claude' : (selectedNode.data.model.includes('gpt') || selectedNode.data.model === 'o3') ? 'openai' : 'google',
model_name: selectedNode.data.model,
temperature: selectedNode.data.temperature,
system_prompt: selectedNode.data.systemPrompt,
@@ -1004,7 +1005,9 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
try {
// Determine provider
+ const isClaude = modelAtSend.includes('claude');
const isOpenAI = modelAtSend.includes('gpt') || modelAtSend === 'o3';
+ const provider = isClaude ? 'claude' : isOpenAI ? 'openai' : 'google';
const reasoningModels = ['gpt-5', 'gpt-5-chat-latest', 'gpt-5-mini', 'gpt-5-nano', 'gpt-5-pro', 'gpt-5.1', 'gpt-5.1-chat-latest', 'gpt-5.2', 'gpt-5.2-chat-latest', 'gpt-5.2-pro', 'o3'];
const isReasoning = reasoningModels.includes(modelAtSend);
@@ -1024,7 +1027,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
scopes,
merge_strategy: 'smart',
config: {
- provider: isOpenAI ? 'openai' : 'google',
+ provider,
model_name: modelAtSend,
temperature: isReasoning ? 1 : tempAtSend,
enable_google_search: webSearchAtSend,
@@ -1424,6 +1427,12 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
}}
className="w-full border border-gray-300 rounded-md p-2 text-sm"
>
+ <optgroup label="Claude">
+ <option value="claude-sonnet-4-5">claude-sonnet-4.5</option>
+ <option value="claude-opus-4">claude-opus-4</option>
+ <option value="claude-opus-4-5">claude-opus-4.5</option>
+ <option value="claude-opus-4-6">claude-opus-4.6</option>
+ </optgroup>
<optgroup label="Gemini">
<option value="gemini-2.5-flash">gemini-2.5-flash</option>
<option value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option>
@@ -1841,7 +1850,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
? 'bg-gray-900 border-gray-700 prose-invert text-gray-200'
: 'bg-gray-50 border-gray-200 text-gray-900'
}`}>
- <ReactMarkdown>{selectedNode.data.response || (streamingNodeId === selectedNode.id ? streamBuffer : '')}</ReactMarkdown>
+ <ReactMarkdown remarkPlugins={[remarkGfm]}>{selectedNode.data.response || (streamingNodeId === selectedNode.id ? streamBuffer : '')}</ReactMarkdown>
</div>
)}
</div>
@@ -2135,7 +2144,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
/>
) : (
<div className="prose prose-sm max-w-none">
- <ReactMarkdown>{selectedNode.data.response}</ReactMarkdown>
+ <ReactMarkdown remarkPlugins={[remarkGfm]}>{selectedNode.data.response}</ReactMarkdown>
</div>
)}
</div>
@@ -2419,6 +2428,12 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
isDark ? 'bg-gray-700 border-gray-600 text-gray-200' : 'border-gray-300 text-gray-900'
}`}
>
+ <optgroup label="Claude">
+ <option value="claude-sonnet-4-5">claude-sonnet-4.5</option>
+ <option value="claude-opus-4">claude-opus-4</option>
+ <option value="claude-opus-4-5">claude-opus-4.5</option>
+ <option value="claude-opus-4-6">claude-opus-4.6</option>
+ </optgroup>
<optgroup label="Gemini">
<option value="gemini-2.5-flash">gemini-2.5-flash</option>
<option value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option>
@@ -2520,7 +2535,7 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle, onInteract }) => {
<p className="whitespace-pre-wrap">{msg.content}</p>
) : (
<div className={`prose prose-sm max-w-none ${isDark ? 'prose-invert' : ''}`}>
- <ReactMarkdown>{msg.content}</ReactMarkdown>
+ <ReactMarkdown remarkPlugins={[remarkGfm]}>{msg.content}</ReactMarkdown>
</div>
)}
</div>