feat(stage-ui): new aihubmix provider, bring back LM Studio, Azure AI Foundry
This commit is contained in:
@@ -5,6 +5,7 @@ dictionaries: []
|
||||
words:
|
||||
- acubismmotion
|
||||
- Aerisita
|
||||
- aihubmix
|
||||
- airi
|
||||
- airi-vtuber
|
||||
- Alaya
|
||||
@@ -153,6 +154,7 @@ words:
|
||||
- live2dcubismframework
|
||||
- livechat
|
||||
- Llmmarker
|
||||
- lmstudio
|
||||
- lobehub
|
||||
- logg
|
||||
- Lorebook
|
||||
|
||||
@@ -121,7 +121,9 @@ pages:
|
||||
scenario: You recently woke up and forgot everything about your previous life.
|
||||
systemprompt: You will receive messages, answer to them like a real human.
|
||||
posthistoryinstructions: Remember to imitate an human.
|
||||
modules_info: Configure modules for this character card. If not set, default module configuration will be used.
|
||||
modules_info: >-
|
||||
Configure modules for this character card. If not set, default module
|
||||
configuration will be used.
|
||||
use_default: Use default
|
||||
use_default_not_configured: Use default (not configured)
|
||||
fields_info:
|
||||
@@ -155,7 +157,6 @@ pages:
|
||||
systemprompt: 'Error: Please, provide a system prompt.'
|
||||
posthistoryinstructions: 'Error: Post history prompt is required.'
|
||||
modules: Modules
|
||||
|
||||
name_asc: Name (A-Z)
|
||||
name_desc: Name (Z-A)
|
||||
no_cards: No cards yet. Click the button above to upload one!
|
||||
@@ -442,7 +443,9 @@ pages:
|
||||
apply-and-restart: Save and restart stdio MCP
|
||||
messages:
|
||||
opened: Config file opened at {path}
|
||||
restarted: MCP servers restarted. Started {started}, failed {failed}, skipped {skipped}
|
||||
restarted: >-
|
||||
MCP servers restarted. Started {started}, failed {failed}, skipped
|
||||
{skipped}
|
||||
providers:
|
||||
explained:
|
||||
chat: Text generation model providers. e.g. OpenRouter, OpenAI, Ollama.
|
||||
@@ -466,7 +469,9 @@ pages:
|
||||
validation:
|
||||
failed:
|
||||
title: Please check your provider settings, validation failed.
|
||||
description: You can still save the current configuration if you want to proceed.
|
||||
description: >-
|
||||
You can still save the current configuration if you want to
|
||||
proceed.
|
||||
action: Save anyway
|
||||
config:
|
||||
common:
|
||||
@@ -520,7 +525,9 @@ pages:
|
||||
needed for making it pass for Ollama. You need to set
|
||||
<code>OLLAMA_HOST</code> explicitly when start the Ollama
|
||||
application or Ollama CLI server, for detailed
|
||||
information, check <a href="https://airi.moeru.ai/docs/en/docs/manual/integrations/providers/chat/ollama">Ollama integration guide</a>.
|
||||
information, check <a
|
||||
href="https://airi.moeru.ai/docs/en/docs/manual/integrations/providers/chat/ollama">Ollama
|
||||
integration guide</a>.
|
||||
common:
|
||||
continueAnyway: Continue Anyway
|
||||
fields:
|
||||
@@ -659,7 +666,9 @@ pages:
|
||||
description: Smaller models load faster but may have slightly lower quality.
|
||||
models:
|
||||
fp32-webgpu:
|
||||
description: Full precision model using WebGPU - Recommended for supported devices
|
||||
description: >-
|
||||
Full precision model using WebGPU - Recommended for supported
|
||||
devices
|
||||
fp32:
|
||||
description: Full precision model
|
||||
fp16:
|
||||
@@ -779,6 +788,9 @@ pages:
|
||||
transcriptions:
|
||||
playground:
|
||||
title: Transcription Playground
|
||||
aihubmix:
|
||||
title: AIHubMix
|
||||
description: https://aihubmix.com (10% off)
|
||||
title: Providers
|
||||
connection:
|
||||
description: Configure WebSocket server connection
|
||||
@@ -846,7 +858,9 @@ pages:
|
||||
title: Polaroid
|
||||
description: Utility for taking shots of models
|
||||
context-flow:
|
||||
description: Inspect incoming context updates and outgoing chat stream events
|
||||
description: >-
|
||||
Inspect incoming context updates and outgoing chat stream
|
||||
events
|
||||
websocket-inspector:
|
||||
title: WebSocket Inspector
|
||||
description: Inspect raw WebSocket traffic
|
||||
@@ -855,7 +869,9 @@ pages:
|
||||
description: Test color extraction
|
||||
providers-transcription-realtime-aliyun-nls:
|
||||
title: Aliyun Real-time Transcriber
|
||||
description: Stream microphone audio to Aliyun NLS and inspect live transcripts
|
||||
description: >-
|
||||
Stream microphone audio to Aliyun NLS and inspect live
|
||||
transcripts
|
||||
performance-playground:
|
||||
title: Performance Playground
|
||||
description: 'Test performance runtime: VRM expressions + TTS lip sync'
|
||||
@@ -988,7 +1004,9 @@ vrm:
|
||||
websocket-secure-enabled:
|
||||
title: Enable Secure WebSocket (WSS)
|
||||
description: >-
|
||||
Enable WSS (WebSocket Secure) to allow HTTPS connections for mobile (pocket) in development mode. This will automatically generate a self-signed certificate.
|
||||
Enable WSS (WebSocket Secure) to allow HTTPS connections for mobile (pocket)
|
||||
in development mode. This will automatically generate a self-signed
|
||||
certificate.
|
||||
wip:
|
||||
title: Work in Progress
|
||||
description: >-
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { createChatProvider, createEmbedProvider, createModelProvider, merge } from '@xsai-ext/providers/utils'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { createOpenAICompatibleValidators } from '../../validators/openai-compatible'
|
||||
import { defineProvider } from '../registry'
|
||||
|
||||
const aihubmixConfigSchema = z.object({
|
||||
apiKey: z
|
||||
.string('API Key'),
|
||||
baseUrl: z
|
||||
.string('Base URL')
|
||||
.optional()
|
||||
.default('https://aihubmix.com/v1/'),
|
||||
})
|
||||
|
||||
type AIHubMixConfig = z.input<typeof aihubmixConfigSchema>
|
||||
|
||||
export const providerAIHubMix = defineProvider<AIHubMixConfig>({
|
||||
id: 'aihubmix',
|
||||
order: 1,
|
||||
name: 'AIHubMix',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.aihubmix.title'),
|
||||
description: 'AIHubMix',
|
||||
descriptionLocalize: ({ t }) => t('settings.pages.providers.provider.aihubmix.description'),
|
||||
tasks: ['chat'],
|
||||
icon: 'i-lobe-icons:aihubmix',
|
||||
iconColor: 'i-lobe-icons:aihubmix-color',
|
||||
|
||||
createProviderConfig: ({ t }) => aihubmixConfigSchema.extend({
|
||||
apiKey: aihubmixConfigSchema.shape.apiKey.meta({
|
||||
labelLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.label'),
|
||||
descriptionLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.description'),
|
||||
placeholderLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.placeholder'),
|
||||
type: 'password',
|
||||
}),
|
||||
baseUrl: aihubmixConfigSchema.shape.baseUrl.meta({
|
||||
labelLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.label'),
|
||||
descriptionLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.description'),
|
||||
placeholderLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.placeholder'),
|
||||
}),
|
||||
}),
|
||||
createProvider(config) {
|
||||
return merge(
|
||||
createChatProvider({ apiKey: config.apiKey, baseURL: config.baseUrl! }),
|
||||
createEmbedProvider({ apiKey: config.apiKey, baseURL: config.baseUrl! }),
|
||||
createModelProvider({ apiKey: config.apiKey, baseURL: config.baseUrl! }),
|
||||
)
|
||||
},
|
||||
|
||||
validationRequiredWhen(config) {
|
||||
return !!config.apiKey?.trim()
|
||||
},
|
||||
validators: {
|
||||
...createOpenAICompatibleValidators({
|
||||
checks: ['model_list'],
|
||||
}),
|
||||
},
|
||||
})
|
||||
@@ -38,7 +38,7 @@ function createAnthropic(apiKey: string, baseURL: string = 'https://api.anthropi
|
||||
|
||||
export const providerAnthropic = defineProvider<AnthropicConfig>({
|
||||
id: 'anthropic',
|
||||
order: 5,
|
||||
order: 6,
|
||||
name: 'Anthropic',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.anthropic.title'),
|
||||
description: 'anthropic.com',
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import type { ModelInfo } from '../../types'
|
||||
|
||||
import { createAzure } from '@xsai-ext/providers/special/create'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { defineProvider } from '../registry'
|
||||
|
||||
const azureAIFoundryConfigSchema = z.object({
|
||||
apiKey: z.string('API Key'),
|
||||
resourceName: z.string('Resource Name'),
|
||||
modelId: z.string('Model ID'),
|
||||
apiVersion: z.string('API Version').optional(),
|
||||
})
|
||||
|
||||
type AzureAIFoundryConfig = z.input<typeof azureAIFoundryConfigSchema>
|
||||
|
||||
export const providerAzureAIFoundry = defineProvider<AzureAIFoundryConfig>({
|
||||
id: 'azure-ai-foundry',
|
||||
order: 17,
|
||||
name: 'Azure AI Foundry',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.azure-ai-foundry.title'),
|
||||
description: 'azure.com',
|
||||
descriptionLocalize: ({ t }) => t('settings.pages.providers.provider.azure-ai-foundry.description'),
|
||||
tasks: ['chat'],
|
||||
icon: 'i-lobe-icons:microsoft',
|
||||
|
||||
createProviderConfig: ({ t }) => azureAIFoundryConfigSchema.extend({
|
||||
apiKey: azureAIFoundryConfigSchema.shape.apiKey.meta({
|
||||
labelLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.label'),
|
||||
descriptionLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.description'),
|
||||
placeholderLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.placeholder'),
|
||||
type: 'password',
|
||||
}),
|
||||
resourceName: azureAIFoundryConfigSchema.shape.resourceName.meta({
|
||||
labelLocalized: 'Resource Name',
|
||||
descriptionLocalized: 'Prefix used in https://<prefix>.services.ai.azure.com',
|
||||
placeholderLocalized: 'my-resource',
|
||||
}),
|
||||
modelId: azureAIFoundryConfigSchema.shape.modelId.meta({
|
||||
labelLocalized: 'Model ID',
|
||||
descriptionLocalized: 'Model ID on Azure AI Foundry',
|
||||
placeholderLocalized: 'gpt-4o',
|
||||
}),
|
||||
apiVersion: azureAIFoundryConfigSchema.shape.apiVersion.meta({
|
||||
labelLocalized: 'API Version',
|
||||
descriptionLocalized: 'API version for snapshot of the models',
|
||||
placeholderLocalized: '2025-04-01-preview',
|
||||
section: 'advanced',
|
||||
}),
|
||||
}),
|
||||
createProvider(config) {
|
||||
return createAzure({
|
||||
apiKey: async () => config.apiKey.trim(),
|
||||
resourceName: config.resourceName.trim(),
|
||||
apiVersion: config.apiVersion?.trim(),
|
||||
}) as any
|
||||
},
|
||||
|
||||
extraMethods: {
|
||||
listModels: async config =>
|
||||
[{
|
||||
id: config.modelId,
|
||||
name: config.modelId,
|
||||
provider: 'azure-ai-foundry',
|
||||
description: '',
|
||||
contextLength: 0,
|
||||
deprecated: false,
|
||||
} satisfies ModelInfo],
|
||||
},
|
||||
validationRequiredWhen(config) {
|
||||
return !!config.apiKey?.trim() || !!config.resourceName?.trim() || !!config.modelId?.trim()
|
||||
},
|
||||
validators: {
|
||||
validateConfig: [
|
||||
({ t }) => ({
|
||||
id: 'azure-ai-foundry:check-config',
|
||||
name: t('settings.pages.providers.catalog.edit.validators.openai-compatible.check-config.title'),
|
||||
validator: async (config) => {
|
||||
const errors: Array<{ error: unknown }> = []
|
||||
const apiKey = typeof config.apiKey === 'string' ? config.apiKey.trim() : ''
|
||||
const resourceName = typeof config.resourceName === 'string' ? config.resourceName.trim() : ''
|
||||
const modelId = typeof config.modelId === 'string' ? config.modelId.trim() : ''
|
||||
|
||||
if (!apiKey)
|
||||
errors.push({ error: new Error('API key is required.') })
|
||||
if (!resourceName)
|
||||
errors.push({ error: new Error('Resource name is required.') })
|
||||
if (!modelId)
|
||||
errors.push({ error: new Error('Model ID is required.') })
|
||||
|
||||
return {
|
||||
errors,
|
||||
reason: errors.length > 0 ? errors.map(item => (item.error as Error).message).join(', ') : '',
|
||||
reasonKey: '',
|
||||
valid: errors.length === 0,
|
||||
}
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
})
|
||||
@@ -17,7 +17,7 @@ type GoogleGenerativeConfig = z.input<typeof googleGenerativeConfigSchema>
|
||||
|
||||
export const providerGoogleGenerativeAI = defineProvider<GoogleGenerativeConfig>({
|
||||
id: 'google-generative-ai',
|
||||
order: 6,
|
||||
order: 8,
|
||||
name: 'Google Gemini',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.google-generative-ai.title'),
|
||||
description: 'ai.google.dev',
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import './openai'
|
||||
import './aihubmix'
|
||||
import './lm-studio'
|
||||
import './openai-compatible'
|
||||
import './n1n'
|
||||
import './openrouter-ai'
|
||||
@@ -21,6 +23,7 @@ import './moonshot-ai'
|
||||
import './modelscope'
|
||||
import './ollama'
|
||||
import './cloudflare-workers-ai'
|
||||
import './azure-ai-foundry'
|
||||
|
||||
export {
|
||||
getDefinedProvider,
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { createChatProvider, createEmbedProvider, createModelProvider, merge } from '@xsai-ext/providers/utils'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { createOpenAICompatibleValidators } from '../../validators/openai-compatible'
|
||||
import { defineProvider } from '../registry'
|
||||
|
||||
const lmStudioConfigSchema = z.object({
|
||||
apiKey: z
|
||||
.string('API Key'),
|
||||
baseUrl: z
|
||||
.string('Base URL')
|
||||
.optional()
|
||||
.default('http://localhost:1234/v1/'),
|
||||
})
|
||||
|
||||
type LMStudioConfig = z.input<typeof lmStudioConfigSchema>
|
||||
|
||||
export const providerLmStudio = defineProvider<LMStudioConfig>({
|
||||
id: 'lm-studio',
|
||||
order: 3,
|
||||
name: 'LM Studio',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.lm-studio.title'),
|
||||
description: 'LM Studio',
|
||||
descriptionLocalize: ({ t }) => t('settings.pages.providers.provider.lm-studio.description'),
|
||||
tasks: ['chat'],
|
||||
icon: 'i-lobe-icons:lmstudio',
|
||||
iconColor: 'i-lobe-icons:lmstudio',
|
||||
|
||||
createProviderConfig: ({ t }) => lmStudioConfigSchema.extend({
|
||||
apiKey: lmStudioConfigSchema.shape.apiKey.meta({
|
||||
labelLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.label'),
|
||||
descriptionLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.description'),
|
||||
placeholderLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.api-key.placeholder'),
|
||||
type: 'password',
|
||||
}),
|
||||
baseUrl: lmStudioConfigSchema.shape.baseUrl.meta({
|
||||
labelLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.label'),
|
||||
descriptionLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.description'),
|
||||
placeholderLocalized: t('settings.pages.providers.catalog.edit.config.common.fields.field.base-url.placeholder'),
|
||||
}),
|
||||
}),
|
||||
createProvider(config) {
|
||||
return merge(
|
||||
createChatProvider({ apiKey: config.apiKey, baseURL: config.baseUrl! }),
|
||||
createEmbedProvider({ apiKey: config.apiKey, baseURL: config.baseUrl! }),
|
||||
createModelProvider({ apiKey: config.apiKey, baseURL: config.baseUrl! }),
|
||||
)
|
||||
},
|
||||
|
||||
validationRequiredWhen(config) {
|
||||
return !!config.apiKey?.trim()
|
||||
},
|
||||
validators: {
|
||||
...createOpenAICompatibleValidators({
|
||||
checks: ['connectivity', 'model_list'],
|
||||
connectivityFailureReason: ({ errorMessage }) =>
|
||||
`Failed to reach LM Studio server, error: ${errorMessage} occurred.\n\nMake sure LM Studio is running and the local server is started. You can start the local server in LM Studio by going to the 'Local Server' tab and clicking 'Start Server'.`,
|
||||
modelListFailureReason: ({ errorMessage }) =>
|
||||
`Failed to reach LM Studio server, error: ${errorMessage} occurred.\n\nMake sure LM Studio is running and the local server is started. You can start the local server in LM Studio by going to the 'Local Server' tab and clicking 'Start Server'.`,
|
||||
}),
|
||||
},
|
||||
})
|
||||
@@ -69,6 +69,8 @@ export const providerOllama = defineProvider({
|
||||
],
|
||||
validateProvider: createOpenAICompatibleValidators({
|
||||
checks: ['connectivity', 'model_list', 'chat_completions'],
|
||||
connectivityFailureReason: ({ errorMessage }) =>
|
||||
`Failed to reach Ollama server, error: ${errorMessage} occurred.\n\nIf you are using Ollama locally, this is likely the CORS (Cross-Origin Resource Sharing) security issue, where you will need to set OLLAMA_ORIGINS=* or OLLAMA_ORIGINS=https://airi.moeru.ai,http://localhost environment variable before launching Ollama server to make this work.`,
|
||||
})!.validateProvider,
|
||||
},
|
||||
business: ({ t }) => ({
|
||||
|
||||
@@ -18,7 +18,7 @@ type OpenAICompatibleConfig = z.input<typeof openAICompatibleConfigSchema>
|
||||
|
||||
export const providerOpenAICompatible = defineProvider<OpenAICompatibleConfig>({
|
||||
id: 'openai-compatible',
|
||||
order: 3,
|
||||
order: 4,
|
||||
name: 'OpenAI Compatible',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.openai-compatible.title'),
|
||||
description: 'OpenAI-compatible chat APIs with API key authentication.',
|
||||
|
||||
@@ -17,7 +17,7 @@ type OpenAICompatibleConfig = z.input<typeof openAICompatibleConfigSchema>
|
||||
|
||||
export const providerOpenAI = defineProvider<OpenAICompatibleConfig>({
|
||||
id: 'openai',
|
||||
order: 1,
|
||||
order: 5,
|
||||
name: 'OpenAI',
|
||||
nameLocalize: ({ t }) => t('settings.pages.providers.provider.openai.title'),
|
||||
description: 'OpenAI',
|
||||
|
||||
@@ -12,6 +12,13 @@ import { isModelProvider } from '../types'
|
||||
|
||||
type OpenAICompatibleValidationCheck = 'connectivity' | 'model_list' | 'chat_completions'
|
||||
|
||||
interface OpenAICompatibleValidationOptions<TConfig extends { apiKey?: string, baseUrl?: string }> {
|
||||
checks?: OpenAICompatibleValidationCheck[]
|
||||
additionalHeaders?: Record<string, string>
|
||||
connectivityFailureReason?: (input: { config: TConfig, error: unknown, errorMessage: string }) => string
|
||||
modelListFailureReason?: (input: { config: TConfig, error: unknown, errorMessage: string }) => string
|
||||
}
|
||||
|
||||
function extractStatusCode(error: unknown): number | null {
|
||||
if (!error)
|
||||
return null
|
||||
@@ -89,10 +96,9 @@ async function pickValidationModel<TConfig extends { apiKey?: string | null, bas
|
||||
}
|
||||
}
|
||||
|
||||
export function createOpenAICompatibleValidators<TConfig extends { apiKey?: string, baseUrl?: string }>(options?: {
|
||||
checks?: OpenAICompatibleValidationCheck[]
|
||||
additionalHeaders?: Record<string, string>
|
||||
}): ProviderDefinition<TConfig>['validators'] {
|
||||
export function createOpenAICompatibleValidators<TConfig extends { apiKey?: string, baseUrl?: string }>(
|
||||
options?: OpenAICompatibleValidationOptions<TConfig>,
|
||||
): ProviderDefinition<TConfig>['validators'] {
|
||||
const checks = options?.checks ?? ['connectivity', 'model_list', 'chat_completions']
|
||||
const additionalHeaders = options?.additionalHeaders
|
||||
|
||||
@@ -100,6 +106,7 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
|
||||
connectivityOk: boolean
|
||||
chatOk: boolean
|
||||
errorMessage?: string
|
||||
error?: unknown
|
||||
}
|
||||
|
||||
const chatCheckCacheKey = 'openai-compatible:chat-check'
|
||||
@@ -109,7 +116,7 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
|
||||
provider: ProviderInstance,
|
||||
providerExtra: ProviderExtraMethods<TConfig> | undefined,
|
||||
contextOptions?: { validationCache?: Map<string, unknown> },
|
||||
) => {
|
||||
): Promise<ChatCheckResult> => {
|
||||
const cache = contextOptions?.validationCache
|
||||
const existing = cache?.get(chatCheckCacheKey) as Promise<ChatCheckResult> | undefined
|
||||
if (existing)
|
||||
@@ -131,11 +138,11 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
|
||||
}
|
||||
catch (e) {
|
||||
if (isNetworkError(e)) {
|
||||
return { connectivityOk: false, chatOk: false, errorMessage: errorMessageFrom(e) }
|
||||
return { connectivityOk: false, chatOk: false, error: e, errorMessage: errorMessageFrom(e) }
|
||||
}
|
||||
|
||||
const status = extractStatusCode(e)
|
||||
const chatOk = status === 400 || (status && status >= 200 && status < 300)
|
||||
const chatOk = status === 400 || Boolean(status && status >= 200 && status < 300)
|
||||
return { connectivityOk: true, chatOk, errorMessage: errorMessageFrom(e) }
|
||||
}
|
||||
}
|
||||
@@ -169,11 +176,11 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
|
||||
}
|
||||
catch (e) {
|
||||
if (isNetworkError(e)) {
|
||||
return { connectivityOk: false, chatOk: false, errorMessage: errorMessageFrom(e) }
|
||||
return { connectivityOk: false, chatOk: false, error: e, errorMessage: errorMessageFrom(e) }
|
||||
}
|
||||
|
||||
const status = extractStatusCode(e)
|
||||
const chatOk = status === 400 || (status && status >= 200 && status < 300)
|
||||
const chatOk = status === 400 || Boolean(status && status >= 200 && status < 300)
|
||||
return { connectivityOk: true, chatOk, errorMessage: errorMessageFrom(e) }
|
||||
}
|
||||
})()
|
||||
@@ -238,7 +245,11 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
|
||||
contextOptions as { validationCache?: Map<string, unknown> } | undefined,
|
||||
)
|
||||
if (!result.connectivityOk) {
|
||||
errors.push({ error: new Error(`Connectivity check failed: ${result.errorMessage || 'Unknown error.'}`) })
|
||||
const errorMessage = result.errorMessage || 'Unknown error.'
|
||||
const reason = options?.connectivityFailureReason
|
||||
? options.connectivityFailureReason({ config, error: result.error, errorMessage })
|
||||
: `Connectivity check failed: ${errorMessage}`
|
||||
errors.push({ error: new Error(reason) })
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -290,7 +301,11 @@ export function createOpenAICompatibleValidators<TConfig extends { apiKey?: stri
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
errors.push({ error: new Error(`Model list check failed: ${(e as Error).message}`) })
|
||||
const errorMessage = errorMessageFrom(e) || 'Unknown error.'
|
||||
const reason = options?.modelListFailureReason
|
||||
? options.modelListFailureReason({ config, error: e, errorMessage })
|
||||
: `Model list check failed: ${errorMessage}`
|
||||
errors.push({ error: new Error(reason) })
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user