## Summary Extract runtime-neutral provider definitions from `@proj-airi/stage-ui` into a new `@proj-airi/provider-inference` package that runs in both Node.js and browser without Vue/Pinia dependencies. ## What changed - **New package** `packages/provider-inference/` — owns `ProviderDefinition`, `ProviderRegistry`, validators, and all provider modules (cloud + local) - **Provider modules relocated** — ~45 providers moved from `stage-ui/src/libs/providers/providers/` to `provider-inference/src/providers/cloud/` and `provider-inference/src/providers/local/` - **Type decoupling** — `ProviderContext.t` changed from `ComposerTranslation` (Vue) to generic `ProviderTranslator`, removing the Vue dependency from core types - **stage-ui types slimmed** — `types.ts` now re-exports from `provider-inference` and only adds the Vue-specific `ProviderViews` extension - **validators/run.ts** — becomes a pass-through re-export - **Registry** — portable `createProviderRegistry()` with deterministic ordering and duplicate-id detection ## Verification ```bash pnpm -F @proj-airi/provider-inference typecheck pnpm -F @proj-airi/provider-inference test:node pnpm -F @proj-airi/provider-inference test:browser pnpm -F @proj-airi/provider-inference build pnpm -F @proj-airi/stage-ui typecheck pnpm -F @proj-airi/stage-web typecheck pnpm -F @proj-airi/stage-tamagotchi typecheck pnpm lint ``` ## Why Provider definitions were tightly coupled to Vue (`ComposerTranslation`, `Component`), preventing reuse in non-Vue runtimes (Node.js services, tests, future Electron backend). This extraction creates a clean boundary: runtime-neutral definitions live in `provider-inference`, while Vue/Pinia-specific concerns stay in `stage-ui`.
67 lines
2.5 KiB
TypeScript
67 lines
2.5 KiB
TypeScript
import type { ChatRequestOptions } from '../../../types'
|
|
|
|
import { createMoonshotai } from '@xsai-ext/providers/create'
|
|
import { z } from 'zod'
|
|
|
|
import { ProviderValidationCheck } from '../../../types'
|
|
import { createOpenAICompatibleValidators } from '../../../validators'
|
|
import { defineProvider } from '../../registry'
|
|
|
|
const moonshotConfigSchema = z.object({
|
|
apiKey: z
|
|
.string('API Key'),
|
|
baseUrl: z
|
|
.string('Base URL')
|
|
.optional()
|
|
.default('https://api.moonshot.ai/v1/'),
|
|
})
|
|
|
|
type MoonshotConfig = z.input<typeof moonshotConfigSchema>
|
|
|
|
export const providerMoonshotAI = defineProvider<MoonshotConfig, 'moonshot-ai'>({
|
|
id: 'moonshot-ai',
|
|
name: 'Moonshot AI',
|
|
nameLocalize: ({ t }) => t('settings.pages.providers.provider.moonshot.title'),
|
|
description: 'moonshot.ai',
|
|
descriptionLocalize: ({ t }) => t('settings.pages.providers.provider.moonshot.description'),
|
|
tasks: ['chat'],
|
|
capabilities: { chat: { reasoning: { modes: ['enabled', 'disabled'] } } },
|
|
icon: 'i-lobe-icons:moonshot',
|
|
|
|
createProviderConfig: ({ t }) => moonshotConfigSchema.extend({
|
|
apiKey: moonshotConfigSchema.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: moonshotConfigSchema.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) {
|
|
const provider = createMoonshotai(config.apiKey, config.baseUrl)
|
|
return {
|
|
...provider,
|
|
chat(model: string, options?: ChatRequestOptions) {
|
|
const request = provider.chat(model)
|
|
if (!options?.reasoning)
|
|
return request
|
|
|
|
return { ...request, thinking: { type: options.reasoning } }
|
|
},
|
|
}
|
|
},
|
|
|
|
validationRequiredWhen(config) {
|
|
return !!config.apiKey?.trim()
|
|
},
|
|
validators: {
|
|
...createOpenAICompatibleValidators({
|
|
checks: [ProviderValidationCheck.Connectivity, ProviderValidationCheck.ModelList, ProviderValidationCheck.ChatCompletions],
|
|
}),
|
|
},
|
|
})
|