Custom Provider Guide
Where the provider system lives, and exactly how to plug in any new AI provider — zero-code or with a tiny file. প্রতিটি ধাপের সাথে বাংলায় বিস্তারিত ব্যাখ্যা দেওয়া আছে। New: you can also manage providers visually with full CRUD in the Admin Panel.
1. How providers work
A provider is any upstream AI service the gateway can chat with. Every provider lives in
src/providers/ and exposes the same tiny contract, so the rest of the
gateway (validation, errors, rate limits, response shape) works identically no matter who answers.
your app ──▶ POST /api/v1/chat { "provider": "poolside", ... }
│
▼
AI Gateway (src/index.js)
│ validate → rate-limit → pick provider (src/providers/registry.js)
▼
┌─────────────────┼──────────────────┐
▼ ▼ ▼
openrouter.js poolside.js custom.js
OpenRouter API Poolside API ANY OpenAI-compatible URL (env-driven)
Provider মানে হলো AI সেবা দেওয়া কোম্পানি (OpenRouter, Poolside, OpenAI ইত্যাদি)। এদের সবাইকে গেটওয়েতে যুক্ত করার জায়গা হলো src/providers/ ফোল্ডার। রেজিস্ট্রি ফাইল (src/providers/registry.js) ঠিক করে কোন কোন provider চালু আছে। আপনি চাইলে কোড না লিখেই (Method 1) অথবা ছোট একটি ফাইল বানিয়ে (Method 2) নতুন provider যোগ করতে পারবেন।
2. Three ways to add a provider
1 — Zero code
Reuse the built-in custom provider: just set 3 env vars. Best for quick tests and one extra vendor.
2 — Provider file
Add a ~15-line file like poolside.js. First-class id, models list, own env keys. Best for permanence.
3 — Template
Copy src/providers/_template.js for a fully annotated skeleton when the provider needs custom logic.
3. Method 1 — Zero code (the custom provider)
The gateway ships with a universal adapter, src/providers/custom.js. It reads
its target from environment variables, so pointing it at a new vendor requires no code and no
redeploy of code — only env vars:
| Env var | Required | Example |
|---|---|---|
CUSTOM_BASE_URL | yes | https://api.openai.com/v1 |
CUSTOM_API_KEY | usually | sk-… (omit for Ollama/LM Studio) |
CUSTOM_MODEL | yes | gpt-4o-mini |
Then call it with "provider": "custom":
curl -X POST https://YOUR-DOMAIN/api/v1/chat \
-H "Content-Type: application/json" \
-d '{
"provider": "custom",
"message": "Hello from my own provider!"
}'
Known-good base URLs
| Vendor | CUSTOM_BASE_URL | CUSTOM_MODEL example |
|---|---|---|
| OpenAI | https://api.openai.com/v1 | gpt-4o-mini |
| DeepSeek | https://api.deepseek.com | deepseek-chat |
| Together | https://api.together.xyz/v1 | meta-llama/Llama-3.3-70B-Instruct-Turbo |
| Ollama (local) | http://localhost:11434/v1 | llama3.2 (no key) |
| LM Studio (local) | http://localhost:1234/v1 | loaded model (no key) |
Method 1 কখন ব্যবহার করবেন: যখন provider-টি OpenAI-এর মতো একই রকম API ব্যবহার করে (বেশিরভাগই করে) এবং আপনি দ্রুত টেস্ট করতে চান। শুধু ৩টি environment variable সেট করুন — CUSTOM_BASE_URL (provider-এর ঠিকানা), CUSTOM_API_KEY (তাদের দেওয়া key), CUSTOM_MODEL (মডেলের নাম)। এরপর রিকোয়েস্টে "provider": "custom" লিখলেই সেই provider উত্তর দেবে। খেয়াল রাখবেন — এই পদ্ধতিতে একসাথে একটি custom provider চলে; একাধিক দরকার হলে Method 2 ব্যবহার করুন।
4. Method 2 — Add a dedicated provider file (recommended)
This is exactly how Poolside AI was added to this project. A provider that speaks the OpenAI protocol needs one tiny file using the factory, then a 2-line registration.
Step 1 — create src/providers/poolside.js
import { createOpenAICompatible } from './openai-compatible.js';
export const poolsideProvider = createOpenAICompatible({
id: 'poolside', // unique, lowercase
label: 'Poolside AI', // shown in /providers
description: 'Poolside Laguna code-intelligence models…',
defaultBaseUrl: 'https://inference.poolside.ai/v1',
envKey: 'POOLSIDE_API_KEY', // env var holding the key
modelEnvKey: 'POOLSIDE_MODEL', // optional model override
defaultModel: 'poolside/laguna-s-2.1',
models: ['poolside/laguna-s-2.1'],
supportsMaxTokens: true,
});
src/providers/ ফোল্ডারে নতুন ফাইল বানান, যেমন poolside.js। ফাইলে উপরের মতো createOpenAICompatible ফ্যাক্টরি কল করুন এবং আপনার provider-এর তথ্য বসান: id (ছোট হাতের অক্ষরে ইউনিক নাম — রিকোয়েস্টে এটাই ব্যবহার হবে), defaultBaseUrl (provider-এর API ঠিকানা, শেষে /v1 থাকে সাধারণত), envKey (যে environment variable-এ API key থাকবে), আর defaultModel (মডেলের নাম)। এটাই মূলত পুরো কাজ!
Step 2 — register it in src/providers/registry.js
import { openrouterProvider } from './openrouter.js';
import { poolsideProvider } from './poolside.js'; // ← 1. import
import { customProvider } from './custom.js';
const BUILT_IN_PROVIDERS = [
openrouterProvider,
poolsideProvider, // ← 2. add to the list
customProvider,
];
registry.js ফাইলে গিয়ে আপনার ফাইলটি import করুন (লাইন ১) এবং BUILT_IN_PROVIDERS তালিকায় যোগ করুন (লাইন ২)। এই তালিকার ক্রম অনুযায়ই GET /api/v1/providers-এ provider দেখা যাবে।
Step 3 — set the API key as an env var
Locally: add POOLSIDE_API_KEY=your-key to .env (Node) or .dev.vars (wrangler). On Cloudflare: see section 7. Never hard-code the key in the file itself.
Step 4 — restart / redeploy
Local: stop (Ctrl+C) and re-run npm start. Cloudflare: push to GitHub and Pages redeploys automatically.
Step 5 — call it
curl https://YOUR-DOMAIN/api/v1/chat \
-X POST \
-H "Content-Type: application/json" \
-d '{ "provider": "poolside",
"model": "poolside/laguna-s-2.1",
"messages": [{ "role": "user", "content": "What are channels in Go?" }] }'
ধাপ ৩: আপনার provider-এর key-টি environment variable-এ রাখুন (নামটি হবে ফাইলে envKey-তে যা লিখেছেন, যেমন POOLSIDE_API_KEY)। Cloudflare-এ দিলে অবশ্যই রিডিপ্লয় লাগবে। ধাপ ৪: লোকালে সার্ভার রিস্টার্ট করুন, Cloudflare-এ push করলেই হবে। ধাপ ৫: এবার রিকোয়েস্টে "provider": "poolside" (আপনার দেওয়া id) পাঠিয়ে চেক করুন। GET /api/v1/providers-এ নতুন provider "configured" দেখালে বুঝবেন সব ঠিক আছে।
5. Method 3 — the template (full control)
If the provider does not speak the OpenAI protocol (different request shape, different auth, custom
response format), copy src/providers/_template.js. It is a fully annotated
skeleton of the provider contract — you implement isConfigured(env) and
chat(payload, ctx) yourself, throw typed ApiErrors,
and register the result exactly like Step 2 above.
export const myProvider = {
id: 'myprovider',
label: 'My Provider',
description: '…',
defaultModel: 'my-model-v1',
models: ['my-model-v1'],
requiredEnvKeys: ['MYPROVIDER_API_KEY'],
isConfigured(env) {
return Boolean(env.MYPROVIDER_API_KEY);
},
async chat(payload, { env, config }) {
// build YOUR request shape, fetch with utils/http.js postJson(),
// map failures with upstreamError() from core/errors.js,
// then return { reply, model, usage } — the gateway does the rest.
},
};
যদি provider-এর API OpenAI-এর মতো না হয় (যেমন Google Gemini-এর পুরনো ফরম্যাট), তাহলে _template.js ফাইলটি কপি করে নিজের মতো লিখুন। দুটি ফাংশন বানাতে হবে — isConfigured() (key আছে কি না) আর chat() (আসল রিকোয়েস্ট)। এরর দিতে হবে core/errors.js-এর ApiError দিয়ে, যাতে সব এরর একই ফরম্যাটে যায়। এরপর registry-তে যোগ করুন — ব্যস।
6. Provider contract reference
Every option accepted by createOpenAICompatible() — the factory used by OpenRouter, Poolside and custom:
| Field | Required | Purpose |
|---|---|---|
id | yes | Unique lowercase id — the value clients pass as "provider". |
label | yes | Human name shown in GET /api/v1/providers. |
description | yes | One-liner for the provider list. |
defaultBaseUrl | yes* | e.g. https://inference.poolside.ai/v1 — or use baseUrlEnvKey to read it from env (how custom.js works). |
envKey | yes | Name of the env var holding the API key. |
apiKeyOptional | no | true for key-less runtimes (Ollama, LM Studio). |
modelEnvKey | yes | Env var that overrides defaultModel. |
defaultModel | yes | Fallback model id. |
models | no | Informational list (shown in the Playground's model picker). |
extraHeadersFn | no | (env) => headers for vendor-specific headers (OpenRouter uses it for attribution). |
supportsMaxTokens | no | Set false if the vendor rejects max_tokens. |
The factory handles everything else: auth header, timeout, error mapping (401→UPSTREAM_AUTH_ERROR, 429→UPSTREAM_RATE_LIMIT…), usage normalization and the success envelope.
7. Setting provider keys on Cloudflare Pages
- Open the Cloudflare dashboard → Workers & Pages → click your Pages project.
- Go to Settings → Variables and Secrets.
- Fastest: click Import .env and upload a prepared env file (all variables at once) — or click + Add, choose type Secret, and enter the name (e.g.
POOLSIDE_API_KEY) and the key value. - Add it to both environments: Production and Preview (tabs at the top of the section).
- Redeploy — Deployments → latest deployment → Retry deployment, or just push any commit. New variables only take effect on a fresh deployment.
.env / .dev.vars git-ignored (already configured).
① Cloudflare ড্যাশবোর্ডে ঢুকুন → Workers & Pages → নিজের প্রজেক্টে ক্লিক করুন। ② Settings ট্যাব → Variables and Secrets অংশে যান। ③ Import .env বাটন দিয়ে প্রস্তুত করা env ফাইল আপলোড করুন (একবারে সব), অথবা + Add চাপুন → টাইপ Secret → নাম দিন (যেমন POOLSIDE_API_KEY) এবং key পেস্ট করুন। ④ Production এবং Preview — দুই জায়গাতেই যোগ করতে ভুলবেন না। ⑤ নতুন variable কাজ করার জন্য একটি নতুন deployment লাগবেই — Deployments থেকে Retry deployment করুন বা ছোট একটি commit push করুন।
8. Verify it works
Two quick checks after deploying:
curl https://YOUR-DOMAIN/api/v1/providers
# → find your provider in the list; "configured": true is required
curl -X POST https://YOUR-DOMAIN/api/v1/chat \
-H "Content-Type: application/json" \
-d '{ "provider": "poolside", "failover": false, "message": "ping" }'
Prefer clicking over curl? The API Status page has a per-provider Test button that runs this check from the browser.
9. FAQ & troubleshooting
Can I add more than one custom provider?
Yes — Method 1's custom slot holds one vendor, but Method 2 lets you add unlimited providers (one file each). Many teams keep custom as their staging playground and promote serious vendors to dedicated files.
How do I know if a vendor is OpenAI-compatible?
If this curl returns JSON with choices[0].message.content, it is compatible:
curl https://VENDOR-URL/v1/chat/completions \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "their-model", "messages": [{ "role": "user", "content": "hi" }] }'
Troubleshooting table
| Symptom | Code | Fix |
|---|---|---|
New provider id gets UNKNOWN_PROVIDER | 400 | Not registered — check registry.js and that you redeployed. |
| "not configured on the server" | PROVIDER_NOT_CONFIGURED | Env var missing or named differently than envKey; remember the redeploy rule. |
| "rejected the API key" | UPSTREAM_AUTH_ERROR | Wrong/revoked key in the env var (no quotes, no spaces). |
| "could not find the requested model" | UPSTREAM_ERROR | Model id typo in defaultModel or the request. |
| "Cannot reach …" | NETWORK_ERROR | Wrong defaultBaseUrl (protocol, path, trailing /v1). |
| Times out on big prompts | UPSTREAM_TIMEOUT | Raise PROVIDER_TIMEOUT_MS. |
| Provider ignores temperature | — | Some vendors only accept specific ranges; set temperature per request or extend the factory call. |
সংক্ষেপে: নতুন provider যোগ করার সবচেয়ে সহজ পথ হলো Method 2 — src/providers/-এ ছোট একটি ফাইল + registry.js-এ ২ লাইন + Cloudflare-এ key। কোনো সমস্যা হলে প্রথমে GET /api/v1/providers দেখুন (provider তালিকায় আছে? configured?), তারপর উপরের টেবিলের এরর কোডের সাথে মেলান। Status পেজের Test বাটন দিয়েও যাচাই করতে পারেন।