fix(web,api): fix edit test connection false negative and gate fetch for unsupported providers
- handleTestInlineModel now accepts optional model_index to fall back to stored credentials when api_key is empty, fixing false negatives when testing edited models - Add supportsFetch to provider registry and FETCHABLE_PROVIDER_KEYS derived set - Gate Fetch Models button to only show for OpenAI-compatible and Ollama providers - Add backend guard in handleFetchModels to reject unsupported providers with clear error
This commit is contained in:
parent
249fa93e95
commit
9a0edf0ae3
6 changed files with 93 additions and 22 deletions
|
|
@ -17,6 +17,18 @@ import (
|
||||||
"github.com/sipeed/picoclaw/pkg/providers"
|
"github.com/sipeed/picoclaw/pkg/providers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// fetchableProviders lists providers that support OpenAI-compatible /models listing.
|
||||||
|
var fetchableProviders = map[string]bool{
|
||||||
|
"openai": true, "deepseek": true, "openrouter": true,
|
||||||
|
"qwen-portal": true, "qwen-intl": true, "moonshot": true,
|
||||||
|
"volcengine": true, "zhipu": true, "groq": true,
|
||||||
|
"mistral": true, "nvidia": true, "cerebras": true,
|
||||||
|
"venice": true, "shengsuanyun": true, "vivgrid": true,
|
||||||
|
"minimax": true, "longcat": true, "modelscope": true,
|
||||||
|
"mimo": true, "avian": true, "zai": true, "novita": true,
|
||||||
|
"litellm": true, "vllm": true, "lmstudio": true, "ollama": true,
|
||||||
|
}
|
||||||
|
|
||||||
// registerModelRoutes binds model list management endpoints to the ServeMux.
|
// registerModelRoutes binds model list management endpoints to the ServeMux.
|
||||||
func (h *Handler) registerModelRoutes(mux *http.ServeMux) {
|
func (h *Handler) registerModelRoutes(mux *http.ServeMux) {
|
||||||
mux.HandleFunc("GET /api/models", h.handleListModels)
|
mux.HandleFunc("GET /api/models", h.handleListModels)
|
||||||
|
|
@ -684,6 +696,7 @@ func (h *Handler) handleTestInlineModel(w http.ResponseWriter, r *http.Request)
|
||||||
APIBase string `json:"api_base"`
|
APIBase string `json:"api_base"`
|
||||||
APIKey string `json:"api_key"`
|
APIKey string `json:"api_key"`
|
||||||
AuthMethod string `json:"auth_method"`
|
AuthMethod string `json:"auth_method"`
|
||||||
|
ModelIndex *int `json:"model_index"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(body, &req); err != nil {
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
||||||
|
|
@ -700,6 +713,21 @@ func (h *Handler) handleTestInlineModel(w http.ResponseWriter, r *http.Request)
|
||||||
m.SetAPIKey(req.APIKey)
|
m.SetAPIKey(req.APIKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When api_key is empty and model_index is provided, fall back to stored credentials.
|
||||||
|
// This lets the edit form test unsaved field changes while using the saved key.
|
||||||
|
if req.APIKey == "" && req.ModelIndex != nil {
|
||||||
|
cfg, err := config.LoadConfig(h.configPath)
|
||||||
|
if err == nil && *req.ModelIndex >= 0 && *req.ModelIndex < len(cfg.ModelList) {
|
||||||
|
stored := cfg.ModelList[*req.ModelIndex]
|
||||||
|
if stored.APIKey() != "" {
|
||||||
|
m.SetAPIKey(stored.APIKey())
|
||||||
|
}
|
||||||
|
if m.APIBase == "" && stored.APIBase != "" {
|
||||||
|
m.APIBase = stored.APIBase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if configuration exists
|
// Check if configuration exists
|
||||||
if !hasModelConfiguration(m) {
|
if !hasModelConfiguration(m) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
@ -784,6 +812,11 @@ func (h *Handler) handleFetchModels(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !fetchableProviders[strings.ToLower(req.Provider)] {
|
||||||
|
http.Error(w, fmt.Sprintf("provider %q does not support model listing", req.Provider), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
apiBase := strings.TrimSpace(req.APIBase)
|
apiBase := strings.TrimSpace(req.APIBase)
|
||||||
if apiBase == "" {
|
if apiBase == "" {
|
||||||
apiBase = providers.DefaultAPIBaseForProtocol(req.Provider)
|
apiBase = providers.DefaultAPIBaseForProtocol(req.Provider)
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ export interface TestModelInlineRequest {
|
||||||
api_base?: string
|
api_base?: string
|
||||||
api_key?: string
|
api_key?: string
|
||||||
auth_method?: string
|
auth_method?: string
|
||||||
|
model_index?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function testModelInline(
|
export async function testModelInline(
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import { FetchModelsDialog } from "./fetch-models-dialog"
|
||||||
import { type FieldValidation, validateModelField } from "./model-validation"
|
import { type FieldValidation, validateModelField } from "./model-validation"
|
||||||
import { ProviderCombobox } from "./provider-combobox"
|
import { ProviderCombobox } from "./provider-combobox"
|
||||||
import { getProviderKey } from "./provider-label"
|
import { getProviderKey } from "./provider-label"
|
||||||
import { PROVIDER_MAP } from "./provider-registry"
|
import { FETCHABLE_PROVIDER_KEYS, PROVIDER_MAP } from "./provider-registry"
|
||||||
import { TestModelDialog } from "./test-model-dialog"
|
import { TestModelDialog } from "./test-model-dialog"
|
||||||
|
|
||||||
interface AddForm {
|
interface AddForm {
|
||||||
|
|
@ -484,16 +484,17 @@ export function AddModelSheet({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
{form.provider && FETCHABLE_PROVIDER_KEYS.has(form.provider) && (
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-7 text-xs"
|
className="h-7 text-xs"
|
||||||
onClick={() => setFetchOpen(true)}
|
onClick={() => setFetchOpen(true)}
|
||||||
disabled={!form.provider}
|
|
||||||
>
|
>
|
||||||
<IconDownload className="size-3" />
|
<IconDownload className="size-3" />
|
||||||
{t("models.fetch.title")}
|
{t("models.fetch.title")}
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
{!form.provider && (
|
{!form.provider && (
|
||||||
<span className="text-muted-foreground text-xs">
|
<span className="text-muted-foreground text-xs">
|
||||||
{t("models.field.selectProviderFirst")}
|
{t("models.field.selectProviderFirst")}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ import { FetchModelsDialog } from "./fetch-models-dialog"
|
||||||
import { type FieldValidation, validateModelField } from "./model-validation"
|
import { type FieldValidation, validateModelField } from "./model-validation"
|
||||||
import { ProviderCombobox } from "./provider-combobox"
|
import { ProviderCombobox } from "./provider-combobox"
|
||||||
import { getProviderKey } from "./provider-label"
|
import { getProviderKey } from "./provider-label"
|
||||||
import { PROVIDER_API_BASES, PROVIDER_MAP } from "./provider-registry"
|
import { FETCHABLE_PROVIDER_KEYS, PROVIDER_API_BASES, PROVIDER_MAP } from "./provider-registry"
|
||||||
import { TestModelDialog } from "./test-model-dialog"
|
import { TestModelDialog } from "./test-model-dialog"
|
||||||
|
|
||||||
interface EditForm {
|
interface EditForm {
|
||||||
|
|
@ -441,16 +441,17 @@ export function EditModelSheet({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
{form.provider && FETCHABLE_PROVIDER_KEYS.has(form.provider) && (
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-7 text-xs"
|
className="h-7 text-xs"
|
||||||
onClick={() => setFetchOpen(true)}
|
onClick={() => setFetchOpen(true)}
|
||||||
disabled={!form.provider}
|
|
||||||
>
|
>
|
||||||
<IconDownload className="size-3" />
|
<IconDownload className="size-3" />
|
||||||
{t("models.fetch.title")}
|
{t("models.fetch.title")}
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|
@ -671,6 +672,7 @@ export function EditModelSheet({
|
||||||
apiBase: form.apiBase,
|
apiBase: form.apiBase,
|
||||||
apiKey: form.apiKey,
|
apiKey: form.apiKey,
|
||||||
authMethod: form.authMethod,
|
authMethod: form.authMethod,
|
||||||
|
modelIndex: model?.index,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ export interface ProviderDefinition {
|
||||||
priority: number
|
priority: number
|
||||||
commonModels?: string[]
|
commonModels?: string[]
|
||||||
aliases?: string[]
|
aliases?: string[]
|
||||||
|
/** Whether this provider supports the OpenAI-compatible /models listing endpoint. */
|
||||||
|
supportsFetch?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PROVIDERS: ProviderDefinition[] = [
|
export const PROVIDERS: ProviderDefinition[] = [
|
||||||
|
|
@ -30,6 +32,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
priority: 100,
|
priority: 100,
|
||||||
commonModels: ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "o1", "o3-mini"],
|
commonModels: ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "o1", "o3-mini"],
|
||||||
aliases: ["gpt"],
|
aliases: ["gpt"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "anthropic",
|
key: "anthropic",
|
||||||
|
|
@ -69,6 +72,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 85,
|
priority: 85,
|
||||||
commonModels: ["deepseek-chat", "deepseek-reasoner"],
|
commonModels: ["deepseek-chat", "deepseek-reasoner"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "openrouter",
|
key: "openrouter",
|
||||||
|
|
@ -84,6 +88,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
"anthropic/claude-sonnet-4",
|
"anthropic/claude-sonnet-4",
|
||||||
"google/gemini-2.0-flash",
|
"google/gemini-2.0-flash",
|
||||||
],
|
],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "qwen-portal",
|
key: "qwen-portal",
|
||||||
|
|
@ -97,6 +102,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
priority: 75,
|
priority: 75,
|
||||||
commonModels: ["qwen-max", "qwen-plus", "qwen-turbo"],
|
commonModels: ["qwen-max", "qwen-plus", "qwen-turbo"],
|
||||||
aliases: ["qwen"],
|
aliases: ["qwen"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "qwen-intl",
|
key: "qwen-intl",
|
||||||
|
|
@ -109,6 +115,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
priority: 74,
|
priority: 74,
|
||||||
commonModels: ["qwen-max", "qwen-plus", "qwen-turbo"],
|
commonModels: ["qwen-max", "qwen-plus", "qwen-turbo"],
|
||||||
aliases: ["qwen-international", "dashscope-intl"],
|
aliases: ["qwen-international", "dashscope-intl"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "moonshot",
|
key: "moonshot",
|
||||||
|
|
@ -120,6 +127,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 70,
|
priority: 70,
|
||||||
commonModels: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
|
commonModels: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "volcengine",
|
key: "volcengine",
|
||||||
|
|
@ -132,6 +140,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 69,
|
priority: 69,
|
||||||
commonModels: ["doubao-1.5-pro", "doubao-1.5-lite"],
|
commonModels: ["doubao-1.5-pro", "doubao-1.5-lite"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "zhipu",
|
key: "zhipu",
|
||||||
|
|
@ -144,6 +153,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 68,
|
priority: 68,
|
||||||
commonModels: ["glm-4-plus", "glm-4-flash"],
|
commonModels: ["glm-4-plus", "glm-4-flash"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "groq",
|
key: "groq",
|
||||||
|
|
@ -155,6 +165,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 65,
|
priority: 65,
|
||||||
commonModels: ["llama-3.3-70b-versatile", "mixtral-8x7b-32768"],
|
commonModels: ["llama-3.3-70b-versatile", "mixtral-8x7b-32768"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "mistral",
|
key: "mistral",
|
||||||
|
|
@ -166,6 +177,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 64,
|
priority: 64,
|
||||||
commonModels: ["mistral-large-latest", "mistral-small-latest"],
|
commonModels: ["mistral-large-latest", "mistral-small-latest"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "nvidia",
|
key: "nvidia",
|
||||||
|
|
@ -177,6 +189,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 63,
|
priority: 63,
|
||||||
commonModels: ["meta/llama-3.1-405b-instruct"],
|
commonModels: ["meta/llama-3.1-405b-instruct"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "cerebras",
|
key: "cerebras",
|
||||||
|
|
@ -188,6 +201,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 62,
|
priority: 62,
|
||||||
commonModels: ["llama3.1-8b", "llama3.1-70b"],
|
commonModels: ["llama3.1-8b", "llama3.1-70b"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "azure",
|
key: "azure",
|
||||||
|
|
@ -227,6 +241,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
commonModels: ["llama3", "mistral", "codellama", "qwen2.5"],
|
commonModels: ["llama3", "mistral", "codellama", "qwen2.5"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "vllm",
|
key: "vllm",
|
||||||
|
|
@ -237,6 +252,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: false,
|
requiresApiKey: false,
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
priority: 49,
|
priority: 49,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "lmstudio",
|
key: "lmstudio",
|
||||||
|
|
@ -247,6 +263,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: false,
|
requiresApiKey: false,
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
priority: 48,
|
priority: 48,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "venice",
|
key: "venice",
|
||||||
|
|
@ -257,6 +274,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 45,
|
priority: 45,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "shengsuanyun",
|
key: "shengsuanyun",
|
||||||
|
|
@ -267,6 +285,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 44,
|
priority: 44,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "vivgrid",
|
key: "vivgrid",
|
||||||
|
|
@ -276,6 +295,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 43,
|
priority: 43,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "minimax",
|
key: "minimax",
|
||||||
|
|
@ -285,6 +305,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 42,
|
priority: 42,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "longcat",
|
key: "longcat",
|
||||||
|
|
@ -294,6 +315,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 41,
|
priority: 41,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "modelscope",
|
key: "modelscope",
|
||||||
|
|
@ -304,6 +326,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 40,
|
priority: 40,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "mimo",
|
key: "mimo",
|
||||||
|
|
@ -314,6 +337,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 39,
|
priority: 39,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "avian",
|
key: "avian",
|
||||||
|
|
@ -323,6 +347,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 38,
|
priority: 38,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "zai",
|
key: "zai",
|
||||||
|
|
@ -333,6 +358,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 37,
|
priority: 37,
|
||||||
aliases: ["z.ai", "z-ai"],
|
aliases: ["z.ai", "z-ai"],
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "novita",
|
key: "novita",
|
||||||
|
|
@ -342,6 +368,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 36,
|
priority: 36,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "litellm",
|
key: "litellm",
|
||||||
|
|
@ -351,6 +378,7 @@ export const PROVIDERS: ProviderDefinition[] = [
|
||||||
requiresApiKey: true,
|
requiresApiKey: true,
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
priority: 35,
|
priority: 35,
|
||||||
|
supportsFetch: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -368,6 +396,10 @@ export const PROVIDER_ALIASES: Record<string, string> = Object.fromEntries(
|
||||||
|
|
||||||
export const KNOWN_PROVIDER_KEYS = new Set(PROVIDERS.map((p) => p.key))
|
export const KNOWN_PROVIDER_KEYS = new Set(PROVIDERS.map((p) => p.key))
|
||||||
|
|
||||||
|
export const FETCHABLE_PROVIDER_KEYS = new Set(
|
||||||
|
PROVIDERS.filter((p) => p.supportsFetch).map((p) => p.key),
|
||||||
|
)
|
||||||
|
|
||||||
export const PROVIDER_ICON_SLUGS: Record<string, string> = Object.fromEntries(
|
export const PROVIDER_ICON_SLUGS: Record<string, string> = Object.fromEntries(
|
||||||
PROVIDERS.filter((p) => p.iconSlug).map((p) => [p.key, p.iconSlug!]),
|
PROVIDERS.filter((p) => p.iconSlug).map((p) => [p.key, p.iconSlug!]),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ export interface TestInlineParams {
|
||||||
apiBase: string
|
apiBase: string
|
||||||
apiKey: string
|
apiKey: string
|
||||||
authMethod: string
|
authMethod: string
|
||||||
|
modelIndex?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TestModelDialogProps {
|
interface TestModelDialogProps {
|
||||||
|
|
@ -62,6 +63,7 @@ export function TestModelDialog({
|
||||||
api_base: inlineParams.apiBase || undefined,
|
api_base: inlineParams.apiBase || undefined,
|
||||||
api_key: inlineParams.apiKey || undefined,
|
api_key: inlineParams.apiKey || undefined,
|
||||||
auth_method: inlineParams.authMethod || undefined,
|
auth_method: inlineParams.authMethod || undefined,
|
||||||
|
model_index: inlineParams.modelIndex,
|
||||||
}
|
}
|
||||||
res = await testModelInline(req)
|
res = await testModelInline(req)
|
||||||
} else if (model) {
|
} else if (model) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue