From 953f1e5b40fb9302fd6299bbdcb477b4d7c26137 Mon Sep 17 00:00:00 2001 From: Thibault Jaigu Date: Thu, 24 Sep 2026 17:04:26 +0200 Subject: [PATCH] feat(ai): add Requesty as an OpenAI-compatible provider Registers Requesty next to OpenRouter: provider type and schemas, base URL, default model, model list, env key, logo, CSP connect-src, English strings and docs. --- README.md | 11 ++++--- _headers | 2 +- docs-site/src/content/docs/ai-generation.md | 1 + .../src/content/docs/tr/ai-generation.md | 1 + nginx/nginx.conf | 8 ++--- public/locales/en/translation.json | 32 +++++++++++++++++++ public/logos/requesty.svg | 1 + .../ai/AdvancedEndpointSection.tsx | 2 +- src/config/aiProviders.ts | 22 +++++++++++++ src/i18n/locales/en/translation.json | 32 +++++++++++++++++++ src/services/aiService.ts | 1 + src/store/aiSettings.ts | 1 + src/store/aiSettingsSchemas.ts | 1 + src/store/types.ts | 1 + 14 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 public/logos/requesty.svg diff --git a/README.md b/README.md index 2f37ead0..804bf04b 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ - + @@ -108,7 +108,7 @@ Every diagramming tool makes a compromise. OpenFlowKit doesn't. | **Lucidchart / Miro** | Cloud lock-in — expensive, account required, your data lives on their servers | | **PlantUML** | Server-dependent rendering — no visual editor, no local-first model | -OpenFlowKit is the **only MIT-licensed tool** that combines a real workspace home, a professional visual canvas, bidirectional diagram-as-code, AI generation from 10 providers (including fully-local Ollama), **automatic icon assignment from 1,600+ tech icons**, anchored auto-layout, hardware-encoded cinematic MP4 export, and a Model Context Protocol server so Claude / Cursor / Windsurf can drive it directly — all with zero server-side storage. +OpenFlowKit is the **only MIT-licensed tool** that combines a real workspace home, a professional visual canvas, bidirectional diagram-as-code, AI generation from 11 providers (including fully-local Ollama), **automatic icon assignment from 1,600+ tech icons**, anchored auto-layout, hardware-encoded cinematic MP4 export, and a Model Context Protocol server so Claude / Cursor / Windsurf can drive it directly — all with zero server-side storage. --- @@ -118,7 +118,7 @@ OpenFlowKit is the **only MIT-licensed tool** that combines a real workspace hom | ------------------------------------- | :---------: | :--------: | :-----: | :-----: | :--------: | | Visual canvas editor | ✅ | ✅ | ✅ | ❌ | ✅ | | Bidirectional diagram-as-code | ✅ | ❌ | ❌ | ✅ | ❌ | -| AI generation (10 providers + Ollama) | ✅ | ❌ | ❌ | ❌ | Limited | +| AI generation (11 providers + Ollama) | ✅ | ❌ | ❌ | ❌ | Limited | | Mermaid import (8 types) | ✅ | ❌ | ⚠️ | ✅ | ❌ | | Auto-icon assignment (1,600+) | ✅ | ❌ | ❌ | ❌ | ❌ | | AWS / Azure / GCP / CNCF icons | ✅ | ❌ | ✅ | Partial | ✅ | @@ -169,7 +169,7 @@ Describe your system in plain English. AI generates a diagram on the canvas with | "AWS Lambda → SQS → DynamoDB" | 3 nodes with AWS icons | | "React frontend → Express → MongoDB → S3" | 4 nodes across developer + AWS catalogs | -10 providers supported: Google Gemini, OpenAI, Anthropic Claude, Groq, Mistral, NVIDIA NIM, Cerebras, OpenRouter, **Ollama (fully local)**, or any custom OpenAI-compatible endpoint. Bad DSL from any provider is now auto-repaired — the model sees its own broken output and the parser error, then returns corrected DSL in a single follow-up turn. +11 providers supported: Google Gemini, OpenAI, Anthropic Claude, Groq, Mistral, NVIDIA NIM, Cerebras, OpenRouter, Requesty, **Ollama (fully local)**, or any custom OpenAI-compatible endpoint. Bad DSL from any provider is now auto-repaired — the model sees its own broken output and the parser error, then returns corrected DSL in a single follow-up turn. --- @@ -188,7 +188,7 @@ That means the app does not create a fake default flow just to get you onto the Flowpilot sits directly in the editor. Describe a system, paste source code, upload a screenshot, or ask it to refine what's already on the canvas. Your API key is stored in your browser and sent directly to the provider — OpenFlowKit's servers never see it. -**10 providers. Bring your own key. Switch any time. One runs entirely on your laptop.** +**11 providers. Bring your own key. Switch any time. One runs entirely on your laptop.** | Provider | Default model | Why use it | | ------------------- | ------------------------------------------ | ----------------------------------------------- | @@ -201,6 +201,7 @@ Flowpilot sits directly in the editor. Describe a system, paste source code, upl | NVIDIA NIM | `meta/llama-4-maverick-17b-128e-instruct` | Enterprise GPU inference | | Cerebras | `gpt-oss-120b` | Ultra-fast on WSE-3 silicon | | OpenRouter | `google/gemini-2.5-pro` | Access 300+ models through one key | +| Requesty | `openai/gpt-4o-mini` | 700+ models, managed failover policies | | **Custom endpoint** | Any model | LM Studio, vLLM, or any OpenAI-compatible API | No proxy. No middleman. Direct browser-to-provider requests. diff --git a/_headers b/_headers index 76aad559..42c5d70a 100644 --- a/_headers +++ b/_headers @@ -3,7 +3,7 @@ X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=() - Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none'; + Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.requesty.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none'; /assets/* Cache-Control: public, max-age=31536000, immutable diff --git a/docs-site/src/content/docs/ai-generation.md b/docs-site/src/content/docs/ai-generation.md index e8c2a0f7..756d471c 100644 --- a/docs-site/src/content/docs/ai-generation.md +++ b/docs-site/src/content/docs/ai-generation.md @@ -49,6 +49,7 @@ The app supports multiple BYOK providers, including: - Cerebras - Mistral - OpenRouter +- Requesty - Custom OpenAI-compatible endpoint This matters because you are not locked to one hosted AI vendor or one billing model. Ollama can run locally with no API key when its daemon and model are available. diff --git a/docs-site/src/content/docs/tr/ai-generation.md b/docs-site/src/content/docs/tr/ai-generation.md index 64871ff9..ef1eb25d 100644 --- a/docs-site/src/content/docs/tr/ai-generation.md +++ b/docs-site/src/content/docs/tr/ai-generation.md @@ -37,6 +37,7 @@ Uygulama birden çok BYOK sağlayıcıyı destekler: - Cerebras - Mistral - OpenRouter +- Requesty - özel OpenAI-uyumlu uç nokta ## AI ne zaman doğru araçtır? diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 1ada7d76..97fdf53b 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -24,7 +24,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.requesty.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; location /assets/ { access_log off; @@ -34,7 +34,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.requesty.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; try_files $uri =404; } @@ -44,7 +44,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.requesty.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; } location / { @@ -53,7 +53,7 @@ server { add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://*.openai.com https://*.anthropic.com https://*.googleapis.com https://api.groq.com https://*.mistral.ai https://*.cerebras.ai https://openrouter.ai https://*.requesty.ai https://*.posthog.com wss://*.openflowkit.com wss://signaling.yjs.dev; img-src 'self' data: blob: https:; font-src 'self' data:; worker-src 'self' blob:; frame-ancestors 'none';" always; try_files $uri $uri/ /index.html; } } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index d2d7a4fe..80d5b589 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -1013,6 +1013,10 @@ "hint": "Le Chat · Codestral · European AI leader", "keySetupNote": "Free tier with generous limits — no credit card needed" }, + "requesty": { + "hint": "LLM gateway · 700+ models · One key", + "keySetupNote": "Pay as you go · Add credits in the Requesty dashboard" + }, "custom": { "hint": "Any OpenAI-compatible endpoint" } @@ -1212,6 +1216,34 @@ "badge": "Vision" } }, + "requesty": { + "openai/gpt-4o-mini": { + "label": "GPT-4o mini", + "hint": "Fast · Cost-efficient", + "category": "Speed", + "badge": "Default" + }, + "gpt-5.4-mini": { + "label": "GPT-5.4 mini", + "hint": "Managed policy · Multi-provider failover", + "category": "Speed" + }, + "claude-sonnet-4-6": { + "label": "Claude Sonnet 4.6", + "hint": "Managed policy · Best coding", + "category": "Flagship" + }, + "gemini-3.5-flash": { + "label": "Gemini 3.5 Flash", + "hint": "Managed policy · Fast multimodal", + "category": "Speed" + }, + "deepseek-v4-flash": { + "label": "DeepSeek V4 Flash", + "hint": "Managed policy · Low cost", + "category": "Speed" + } + }, "custom": { "custom": { "label": "Custom Model", diff --git a/public/logos/requesty.svg b/public/logos/requesty.svg new file mode 100644 index 00000000..dfa0c97b --- /dev/null +++ b/public/logos/requesty.svg @@ -0,0 +1 @@ +Requesty diff --git a/src/components/SettingsModal/ai/AdvancedEndpointSection.tsx b/src/components/SettingsModal/ai/AdvancedEndpointSection.tsx index 3d5ed5d1..b94a2e71 100644 --- a/src/components/SettingsModal/ai/AdvancedEndpointSection.tsx +++ b/src/components/SettingsModal/ai/AdvancedEndpointSection.tsx @@ -61,7 +61,7 @@ export function AdvancedEndpointSection({ {t('settingsModal.ai.resetEndpoint', { defaultValue: 'Reset to default' })} - {(currentProvider === 'custom' || currentProvider === 'openrouter' || !!customBaseUrl) && ( + {(currentProvider === 'custom' || currentProvider === 'openrouter' || currentProvider === 'requesty' || !!customBaseUrl) && (

Must support POST /chat/completions (OpenAI format) diff --git a/src/config/aiProviders.ts b/src/config/aiProviders.ts index e065c0c1..c7b86506 100644 --- a/src/config/aiProviders.ts +++ b/src/config/aiProviders.ts @@ -7,6 +7,7 @@ export const PROVIDER_BASE_URLS: Record = { cerebras: 'gpt-oss-120b', mistral: 'mistral-large-latest', openrouter: 'google/gemini-2.5-pro', + requesty: 'openai/gpt-4o-mini', ollama: 'llama3.2', custom: 'gpt-4o', }; @@ -130,6 +132,17 @@ export const PROVIDERS: ProviderMeta[] = [ consoleName: 'OpenRouter Dashboard', defaultModel: getDefaultModel('openrouter'), }, + { + id: 'requesty', + name: 'Requesty', + icon: '⇄', + color: '#1677FF', + logoPath: '/logos/requesty.svg', + keyPlaceholder: 'rqsty-...', + keyLink: 'https://app.requesty.ai/api-keys', + consoleName: 'Requesty Dashboard', + defaultModel: getDefaultModel('requesty'), + }, { id: 'ollama', name: 'Ollama (local)', @@ -210,6 +223,13 @@ export const PROVIDER_MODELS: Record, cerebras: PROVIDER_BASE_URLS.cerebras, mistral: PROVIDER_BASE_URLS.mistral, openrouter: PROVIDER_BASE_URLS.openrouter, + requesty: PROVIDER_BASE_URLS.requesty, ollama: PROVIDER_BASE_URLS.ollama, custom: 'https://api.example.com/v1', }; @@ -245,6 +266,7 @@ export type ProviderRisk = 'browser_friendly' | 'mixed' | 'proxy_likely'; export const PROVIDER_RISK: Record = { gemini: 'browser_friendly', openrouter: 'browser_friendly', + requesty: 'browser_friendly', openai: 'mixed', claude: 'mixed', groq: 'proxy_likely', diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index d2d7a4fe..80d5b589 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -1013,6 +1013,10 @@ "hint": "Le Chat · Codestral · European AI leader", "keySetupNote": "Free tier with generous limits — no credit card needed" }, + "requesty": { + "hint": "LLM gateway · 700+ models · One key", + "keySetupNote": "Pay as you go · Add credits in the Requesty dashboard" + }, "custom": { "hint": "Any OpenAI-compatible endpoint" } @@ -1212,6 +1216,34 @@ "badge": "Vision" } }, + "requesty": { + "openai/gpt-4o-mini": { + "label": "GPT-4o mini", + "hint": "Fast · Cost-efficient", + "category": "Speed", + "badge": "Default" + }, + "gpt-5.4-mini": { + "label": "GPT-5.4 mini", + "hint": "Managed policy · Multi-provider failover", + "category": "Speed" + }, + "claude-sonnet-4-6": { + "label": "Claude Sonnet 4.6", + "hint": "Managed policy · Best coding", + "category": "Flagship" + }, + "gemini-3.5-flash": { + "label": "Gemini 3.5 Flash", + "hint": "Managed policy · Fast multimodal", + "category": "Speed" + }, + "deepseek-v4-flash": { + "label": "DeepSeek V4 Flash", + "hint": "Managed policy · Low cost", + "category": "Speed" + } + }, "custom": { "custom": { "label": "Custom Model", diff --git a/src/services/aiService.ts b/src/services/aiService.ts index 13b07fa2..4674b87c 100644 --- a/src/services/aiService.ts +++ b/src/services/aiService.ts @@ -39,6 +39,7 @@ function getEnvApiKey(provider: AIProvider): string | undefined { case 'cerebras': return import.meta.env.VITE_CEREBRAS_API_KEY; case 'mistral': return import.meta.env.VITE_MISTRAL_API_KEY; case 'openrouter': return import.meta.env.VITE_OPENROUTER_API_KEY; + case 'requesty': return import.meta.env.VITE_REQUESTY_API_KEY; case 'ollama': return import.meta.env.VITE_OLLAMA_API_KEY; case 'custom': return import.meta.env.VITE_CUSTOM_AI_API_KEY; default: return undefined; diff --git a/src/store/aiSettings.ts b/src/store/aiSettings.ts index 160f650c..50288b1a 100644 --- a/src/store/aiSettings.ts +++ b/src/store/aiSettings.ts @@ -9,6 +9,7 @@ export const AI_PROVIDERS = [ 'cerebras', 'mistral', 'openrouter', + 'requesty', 'ollama', 'custom', ] as const satisfies readonly AIProvider[]; diff --git a/src/store/aiSettingsSchemas.ts b/src/store/aiSettingsSchemas.ts index 9f0d42db..fc366e04 100644 --- a/src/store/aiSettingsSchemas.ts +++ b/src/store/aiSettingsSchemas.ts @@ -10,6 +10,7 @@ export const aiProviderSchema = z.enum([ 'cerebras', 'mistral', 'openrouter', + 'requesty', 'ollama', 'custom', ] satisfies [AIProvider, ...AIProvider[]]); diff --git a/src/store/types.ts b/src/store/types.ts index 9fc7f1ad..e5f9b72b 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -47,6 +47,7 @@ export type AIProvider = | 'cerebras' | 'mistral' | 'openrouter' + | 'requesty' | 'ollama' | 'custom';

✨ Mermaid → Icons
Paste Mermaid · 1,600+ icons
auto-assigned · beautiful
🤖 AI Generation
10 providers inc. local Ollama
Direct-to-canvas output
🤖 AI Generation
11 providers inc. local Ollama
Direct-to-canvas output
`{}` Diagram as Code
Bidirectional live sync
Git-friendly DSL
🧩 Asset Libraries
Developer · AWS · Azure
GCP · CNCF · Icons
🎬 Cinematic MP4
WebCodecs H.264
Faster-than-realtime