AgentConnect: cover all AI providers + external agents; Settings: Help section
AgentConnect.jsx rewritten: - Option 1: Built-in AI Coach — lists all 8 providers with free tier badges and 'Get key' links, step-by-step setup instructions - Option 2: External AI Agent (MCP) — Claude Desktop (with Windows path), Claude Code CLI, Cursor, Windsurf/other - Page renamed from 'Connect Your AI Agent' to 'Connect AI' Settings.jsx: - Added Help & Support section: Report a Bug (GitHub Issues), Ask a Question (GitHub Discussions), Star on GitHub
This commit is contained in:
parent
e1b213a54e
commit
8728776f21
2 changed files with 159 additions and 18 deletions
|
|
@ -39,6 +39,17 @@ function CodeBlock({ children, copyText }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AI_PROVIDERS = [
|
||||||
|
{ name: 'OpenRouter', desc: '300+ models, one key. 26 free models.', url: 'https://openrouter.ai/keys', free: true },
|
||||||
|
{ name: 'Groq', desc: 'Ultra-fast Llama inference.', url: 'https://console.groq.com/keys', free: true },
|
||||||
|
{ name: 'Hugging Face', desc: 'Thousands of open-source models.', url: 'https://huggingface.co/settings/tokens', free: true },
|
||||||
|
{ name: 'Ollama', desc: 'Run LLMs locally. No key needed.', url: 'https://ollama.com/', free: true },
|
||||||
|
{ name: 'Google Gemini', desc: 'Gemini 2.0 Flash, 2.5 Pro.', url: 'https://aistudio.google.com/apikey', free: true },
|
||||||
|
{ name: 'OpenAI', desc: 'GPT-4o, GPT-4o-mini.', url: 'https://platform.openai.com/api-keys', free: false },
|
||||||
|
{ name: 'Anthropic Claude', desc: 'Claude Sonnet 4.6, Opus 4.8.', url: 'https://console.anthropic.com/', free: false },
|
||||||
|
{ name: 'Custom', desc: 'Any OpenAI-compatible endpoint.', url: '', free: false },
|
||||||
|
]
|
||||||
|
|
||||||
export default function AgentConnect() {
|
export default function AgentConnect() {
|
||||||
const [config, setConfig] = useState(null)
|
const [config, setConfig] = useState(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
@ -67,30 +78,89 @@ export default function AgentConnect() {
|
||||||
}
|
}
|
||||||
}, null, 2)
|
}, null, 2)
|
||||||
|
|
||||||
|
const cursorConfig = JSON.stringify({
|
||||||
|
"mcpServers": {
|
||||||
|
"diligence": {
|
||||||
|
"url": config.mcp_url,
|
||||||
|
...(config.api_token ? { "headers": { "Authorization": `Bearer ${config.api_token}` } } : {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, null, 2)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<a href="/settings/integrations" style={{
|
<a href="/settings/integrations" style={{
|
||||||
fontSize: '0.82rem', color: 'var(--accent)', textDecoration: 'none',
|
fontSize: '0.82rem', color: 'var(--accent)', textDecoration: 'none',
|
||||||
display: 'inline-block', marginBottom: '12px',
|
display: 'inline-block', marginBottom: '12px',
|
||||||
}}>
|
}}>
|
||||||
← Back to Integrations
|
← Back to Integrations
|
||||||
</a>
|
</a>
|
||||||
<div style={{ marginBottom: '20px' }}>
|
<div style={{ marginBottom: '20px' }}>
|
||||||
<h1 style={{
|
<h1 style={{
|
||||||
fontFamily: 'var(--font-display)', fontWeight: 800,
|
fontFamily: 'var(--font-display)', fontWeight: 800,
|
||||||
fontSize: '1.3rem', marginBottom: '4px',
|
fontSize: '1.3rem', marginBottom: '4px',
|
||||||
}}>
|
}}>
|
||||||
Connect Your AI Agent
|
Connect AI
|
||||||
</h1>
|
</h1>
|
||||||
<p style={{ color: 'var(--text-3)', fontSize: '0.85rem' }}>
|
<p style={{ color: 'var(--text-3)', fontSize: '0.85rem' }}>
|
||||||
Use any MCP-compatible AI to log workouts, track food, and manage your fitness.
|
Two ways to use AI with Diligence: the built-in chat, or an external agent.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Connection Details */}
|
{/* === OPTION 1: Built-in AI Coach === */}
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="section-label">Connection</div>
|
<div className="section-label">Option 1 — Built-in AI Coach</div>
|
||||||
|
<p style={{ fontSize: '0.85rem', color: 'var(--text-2)', marginBottom: '14px' }}>
|
||||||
|
Get an API key from any provider below, paste it into{' '}
|
||||||
|
<a href="/settings/integrations#ai-coaching" style={{ color: 'var(--accent)', fontWeight: 600 }}>
|
||||||
|
Settings → Integrations
|
||||||
|
</a>, then open the <strong>Coach</strong> tab. One key is all you need.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div style={{ display: 'grid', gap: '8px' }}>
|
||||||
|
{AI_PROVIDERS.map(p => (
|
||||||
|
<div key={p.name} style={{
|
||||||
|
display: 'flex', alignItems: 'center', gap: '10px',
|
||||||
|
padding: '10px 0', borderBottom: '1px solid var(--divider)',
|
||||||
|
}}>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||||
|
<span style={{ fontWeight: 700, fontSize: '0.88rem' }}>{p.name}</span>
|
||||||
|
{p.free && (
|
||||||
|
<span style={{
|
||||||
|
fontSize: '0.6rem', padding: '1px 6px', borderRadius: 10,
|
||||||
|
background: 'var(--green-bg)', color: 'var(--green)',
|
||||||
|
fontWeight: 700, fontFamily: 'var(--font-mono)',
|
||||||
|
}}>FREE</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div style={{ fontSize: '0.78rem', color: 'var(--text-3)' }}>{p.desc}</div>
|
||||||
|
</div>
|
||||||
|
{p.url && (
|
||||||
|
<a href={p.url} target="_blank" rel="noopener noreferrer"
|
||||||
|
className="btn-outline btn-sm"
|
||||||
|
style={{ fontSize: '0.72rem', textDecoration: 'none', whiteSpace: 'nowrap' }}>
|
||||||
|
Get key →
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style={{ fontSize: '0.75rem', color: 'var(--text-3)', marginTop: '14px' }}>
|
||||||
|
After getting a key: <strong>Settings → Integrations → AI Coaching</strong> → paste your key → open the <strong>Coach</strong> tab.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* === OPTION 2: External AI Agents (MCP) === */}
|
||||||
|
<div className="card">
|
||||||
|
<div className="section-label">Option 2 — External AI Agent (MCP)</div>
|
||||||
|
<p style={{ fontSize: '0.85rem', color: 'var(--text-2)', marginBottom: '14px' }}>
|
||||||
|
Connect an MCP-compatible AI tool to control Diligence from outside the app.
|
||||||
|
The agent can log workouts, track food, check progress, and manage rewards.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Connection Details */}
|
||||||
<div style={{ marginBottom: '14px' }}>
|
<div style={{ marginBottom: '14px' }}>
|
||||||
<div style={{ fontSize: '0.75rem', color: 'var(--text-3)', fontWeight: 600, marginBottom: '4px' }}>
|
<div style={{ fontSize: '0.75rem', color: 'var(--text-3)', fontWeight: 600, marginBottom: '4px' }}>
|
||||||
MCP Endpoint
|
MCP Endpoint
|
||||||
|
|
@ -145,18 +215,9 @@ export default function AgentConnect() {
|
||||||
API token is set but only visible to admin users.
|
API token is set but only visible to admin users.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div style={{
|
|
||||||
display: 'flex', gap: '12px', flexWrap: 'wrap',
|
|
||||||
fontSize: '0.78rem', color: 'var(--text-3)',
|
|
||||||
}}>
|
|
||||||
<span>{config.tools_count} tools available</span>
|
|
||||||
<span style={{ color: 'var(--divider)' }}>|</span>
|
|
||||||
<span>{config.deployment === 'local' ? 'Local (SQLite)' : 'Docker (PostgreSQL)'}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Claude Desktop Setup */}
|
{/* Claude Desktop */}
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="section-label">Claude Desktop</div>
|
<div className="section-label">Claude Desktop</div>
|
||||||
<p style={{ fontSize: '0.82rem', color: 'var(--text-2)', marginBottom: '12px' }}>
|
<p style={{ fontSize: '0.82rem', color: 'var(--text-2)', marginBottom: '12px' }}>
|
||||||
|
|
@ -166,15 +227,18 @@ export default function AgentConnect() {
|
||||||
{claudeDesktopConfig}
|
{claudeDesktopConfig}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
<p style={{ fontSize: '0.75rem', color: 'var(--text-3)', marginTop: '10px' }}>
|
<p style={{ fontSize: '0.75rem', color: 'var(--text-3)', marginTop: '10px' }}>
|
||||||
On macOS: <code style={{ fontFamily: 'var(--font-mono)', fontSize: '0.72rem' }}>
|
macOS: <code style={{ fontFamily: 'var(--font-mono)', fontSize: '0.72rem' }}>
|
||||||
~/Library/Application Support/Claude/claude_desktop_config.json
|
~/Library/Application Support/Claude/claude_desktop_config.json
|
||||||
|
</code><br />
|
||||||
|
Windows: <code style={{ fontFamily: 'var(--font-mono)', fontSize: '0.72rem' }}>
|
||||||
|
%APPDATA%\Claude\claude_desktop_config.json
|
||||||
</code>
|
</code>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Claude Code Setup */}
|
{/* Claude Code */}
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="section-label">Claude Code</div>
|
<div className="section-label">Claude Code (CLI)</div>
|
||||||
<p style={{ fontSize: '0.82rem', color: 'var(--text-2)', marginBottom: '12px' }}>
|
<p style={{ fontSize: '0.82rem', color: 'var(--text-2)', marginBottom: '12px' }}>
|
||||||
Add the MCP server from your terminal:
|
Add the MCP server from your terminal:
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -183,6 +247,27 @@ export default function AgentConnect() {
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Cursor */}
|
||||||
|
<div className="card">
|
||||||
|
<div className="section-label">Cursor</div>
|
||||||
|
<p style={{ fontSize: '0.82rem', color: 'var(--text-2)', marginBottom: '12px' }}>
|
||||||
|
Add to <code style={{ fontFamily: 'var(--font-mono)', fontSize: '0.72rem' }}>.cursor/mcp.json</code> in your project:
|
||||||
|
</p>
|
||||||
|
<CodeBlock copyText={cursorConfig}>
|
||||||
|
{cursorConfig}
|
||||||
|
</CodeBlock>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Windsurf / Other */}
|
||||||
|
<div className="card">
|
||||||
|
<div className="section-label">Windsurf / Other MCP Tools</div>
|
||||||
|
<p style={{ fontSize: '0.82rem', color: 'var(--text-2)', marginBottom: '12px' }}>
|
||||||
|
Any MCP-compatible tool can connect using the endpoint and token above.
|
||||||
|
Use the same JSON format as Cursor — add a server named "diligence"
|
||||||
|
pointing to the MCP endpoint URL.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* What your agent can do */}
|
{/* What your agent can do */}
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="section-label">What Your Agent Can Do</div>
|
<div className="section-label">What Your Agent Can Do</div>
|
||||||
|
|
@ -208,6 +293,9 @@ export default function AgentConnect() {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{ fontSize: '0.72rem', color: 'var(--text-3)', marginTop: '12px' }}>
|
||||||
|
{config.tools_count} tools available · {config.deployment === 'local' ? 'Local (SQLite)' : 'Docker (PostgreSQL)'}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,59 @@ export default function Settings() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Help & Support */}
|
||||||
|
<div className="card">
|
||||||
|
<div className="section-label">Help & Support</div>
|
||||||
|
<div
|
||||||
|
onClick={() => window.open('https://github.com/DiligenceWorks/Diligence/issues', '_blank')}
|
||||||
|
style={{
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
||||||
|
padding: '14px 0', borderBottom: '1px solid var(--divider)', cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
|
<span style={{ fontSize: '1.2rem' }}>🐛</span>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontWeight: 700, fontSize: '0.95rem' }}>Report a Bug</div>
|
||||||
|
<div style={{ fontSize: '0.78rem', color: 'var(--text-3)', fontWeight: 500 }}>Open an issue on GitHub</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span style={{ color: 'var(--text-3)', fontSize: '1.1rem' }}>›</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
onClick={() => window.open('https://github.com/DiligenceWorks/Diligence/discussions', '_blank')}
|
||||||
|
style={{
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
||||||
|
padding: '14px 0', borderBottom: '1px solid var(--divider)', cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
|
<span style={{ fontSize: '1.2rem' }}>💬</span>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontWeight: 700, fontSize: '0.95rem' }}>Ask a Question</div>
|
||||||
|
<div style={{ fontSize: '0.78rem', color: 'var(--text-3)', fontWeight: 500 }}>GitHub Discussions</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span style={{ color: 'var(--text-3)', fontSize: '1.1rem' }}>›</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
onClick={() => window.open('https://github.com/DiligenceWorks/Diligence', '_blank')}
|
||||||
|
style={{
|
||||||
|
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
||||||
|
padding: '14px 0', cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
|
<span style={{ fontSize: '1.2rem' }}>⭐</span>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontWeight: 700, fontSize: '0.95rem' }}>Star on GitHub</div>
|
||||||
|
<div style={{ fontSize: '0.78rem', color: 'var(--text-3)', fontWeight: 500 }}>DiligenceWorks/Diligence</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span style={{ color: 'var(--text-3)', fontSize: '1.1rem' }}>›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button className="btn-danger btn-full" style={{ marginTop: '10px' }} onClick={() => { clearToken(); navigate('/login') }}>
|
<button className="btn-danger btn-full" style={{ marginTop: '10px' }} onClick={() => { clearToken(); navigate('/login') }}>
|
||||||
Sign Out
|
Sign Out
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue