Skip to content

Commit 9dd1899

Browse files
committed
Added custom provider in wizard
1 parent cfcdc35 commit 9dd1899

1 file changed

Lines changed: 94 additions & 2 deletions

File tree

setup-wizard/index.html

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,10 @@ <h2 style="text-align:center">Configuration Saved!</h2>
586586
id: "azure", name: "Azure OpenAI", desc: "Enterprise Azure-hosted models", tag: "Enterprise", free: false,
587587
baseUrl: "", api: "openai-responses"
588588
},
589+
{
590+
id: "custom", name: "Custom Provider", desc: "Any OpenAI-compatible API endpoint", tag: "Advanced", free: false,
591+
baseUrl: "", api: "openai-completions"
592+
},
589593
];
590594

591595
let currentStep = 0;
@@ -641,14 +645,21 @@ <h2 style="text-align:center">Configuration Saved!</h2>
641645
const providerIds = Object.keys(providers);
642646
if (providerIds.length > 0) {
643647
const pid = providerIds[0];
644-
selectProviderCard(pid);
648+
const knownProviderIds = PROVIDERS.map(p => p.id);
649+
const isKnown = knownProviderIds.includes(pid);
650+
const cardId = isKnown ? pid : "custom";
651+
selectProviderCard(cardId);
645652

646653
// Store loaded provider details for step 2 pre-fill
647-
existingConfig._loadedProvider = pid;
654+
existingConfig._loadedProvider = cardId;
648655
existingConfig._loadedApiKey = providers[pid].apiKey || "";
649656
existingConfig._loadedBaseUrl = providers[pid].baseUrl || "";
650657
const models = providers[pid].models || [];
651658
existingConfig._loadedModelId = models.length > 0 ? models[0].id : "";
659+
if (!isKnown) {
660+
existingConfig._loadedCustomName = pid;
661+
existingConfig._loadedCustomApi = providers[pid].api || "openai-completions";
662+
}
652663
}
653664

654665
// Telegram
@@ -786,6 +797,64 @@ <h2>Configure ${p.name}</h2>
786797
</div>
787798
`;
788799
setupCustomModelToggle(azureDeployment);
800+
} else if (p.id === "custom") {
801+
let customName = "";
802+
let customBaseUrl = "";
803+
let customApiKey = "";
804+
let customModelId = "";
805+
let customApi = "openai-completions";
806+
if (existingConfig && existingConfig._loadedProvider === "custom") {
807+
customBaseUrl = existingConfig._loadedBaseUrl || "";
808+
customApiKey = existingConfig._loadedApiKey || "";
809+
customModelId = existingConfig._loadedModelId || "";
810+
const provCfg = existingConfig.models && existingConfig.models.providers && existingConfig.models.providers.custom;
811+
if (provCfg) customApi = provCfg.api || "openai-completions";
812+
customName = existingConfig._loadedCustomName || "";
813+
}
814+
815+
container.innerHTML = `
816+
<h2>Configure Custom Provider</h2>
817+
<div class="subtitle">Connect to any OpenAI-compatible API endpoint (NVIDIA, Moonshot/Kimi, vLLM, LiteLLM, etc.)</div>
818+
<div class="field">
819+
<label>Provider Name</label>
820+
<div class="hint">A short name for this provider (e.g. "nvidia", "kimi"). Used internally as an identifier.</div>
821+
<input type="text" id="custom-provider-name" placeholder="nvidia" value="${customName}">
822+
</div>
823+
<div class="field">
824+
<label>Base URL</label>
825+
<div class="hint">The API base URL (e.g. https://integrate.api.nvidia.com/v1)</div>
826+
<input type="text" id="custom-base-url" placeholder="https://integrate.api.nvidia.com/v1" value="${customBaseUrl}">
827+
</div>
828+
<div class="field">
829+
<label>API Key</label>
830+
<div class="hint">Your API key for this provider.</div>
831+
<input type="password" id="api-key" placeholder="Paste your API key here" value="${customApiKey}">
832+
</div>
833+
<div class="field">
834+
<label>Model ID</label>
835+
<div class="hint">The exact model identifier (e.g. moonshotai/kimi-k2.5, meta/llama-3.1-70b-instruct)</div>
836+
<input type="text" id="custom-model-id" placeholder="moonshotai/kimi-k2.5" value="${customModelId}">
837+
</div>
838+
<div class="field">
839+
<label>API Type</label>
840+
<div class="hint">Most custom providers use the OpenAI-compatible completions API.</div>
841+
<select id="custom-api-type">
842+
<option value="openai-completions" ${customApi === 'openai-completions' ? 'selected' : ''}>OpenAI Completions (most common)</option>
843+
<option value="openai-responses" ${customApi === 'openai-responses' ? 'selected' : ''}>OpenAI Responses</option>
844+
<option value="anthropic-messages" ${customApi === 'anthropic-messages' ? 'selected' : ''}>Anthropic Messages</option>
845+
</select>
846+
</div>
847+
<div class="field">
848+
<label>Context Window <span class="optional-badge">optional</span></label>
849+
<div class="hint">Max input tokens (default: 128000)</div>
850+
<input type="number" id="custom-context-window" placeholder="128000" value="">
851+
</div>
852+
<div class="field">
853+
<label>Max Output Tokens <span class="optional-badge">optional</span></label>
854+
<div class="hint">Max tokens the model can generate (default: 16384)</div>
855+
<input type="number" id="custom-max-tokens" placeholder="16384" value="">
856+
</div>
857+
`;
789858
} else {
790859
// Cloud providers with model selection
791860
const keyLabels = {
@@ -992,6 +1061,29 @@ <h2>Configure ${p.name}</h2>
9921061
}]
9931062
};
9941063
config.agents.defaults.model.primary = `azure/${modelId}`;
1064+
} else if (p.id === "custom") {
1065+
const providerName = (document.getElementById("custom-provider-name").value.trim() || "custom").toLowerCase().replace(/[^a-z0-9_-]/g, "-");
1066+
const baseUrl = document.getElementById("custom-base-url").value.trim();
1067+
const apiKey = document.getElementById("api-key").value.trim();
1068+
const modelId = document.getElementById("custom-model-id").value.trim() || "default";
1069+
const apiType = document.getElementById("custom-api-type").value;
1070+
const contextWindow = parseInt(document.getElementById("custom-context-window").value) || 128000;
1071+
const maxTokens = parseInt(document.getElementById("custom-max-tokens").value) || 16384;
1072+
1073+
config.models.providers[providerName] = {
1074+
baseUrl: baseUrl,
1075+
apiKey: apiKey,
1076+
api: apiType,
1077+
models: [{
1078+
id: modelId,
1079+
name: modelId,
1080+
reasoning: false,
1081+
input: ["text"],
1082+
contextWindow: contextWindow,
1083+
maxTokens: maxTokens
1084+
}]
1085+
};
1086+
config.agents.defaults.model.primary = `${providerName}/${modelId}`;
9951087
} else {
9961088
const apiKey = document.getElementById("api-key").value.trim();
9971089
const model = getSelectedModel();

0 commit comments

Comments
 (0)