## 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`.
91 lines
3.3 KiB
TypeScript
91 lines
3.3 KiB
TypeScript
import type { ModelInfo } from '../../../types'
|
|
|
|
import { createPerplexity } from '@xsai-ext/providers/create'
|
|
import { z } from 'zod'
|
|
|
|
import { ProviderValidationCheck } from '../../../types'
|
|
import { createOpenAICompatibleValidators } from '../../../validators'
|
|
import { defineProvider } from '../../registry'
|
|
|
|
const perplexityConfigSchema = z.object({
|
|
apiKey: z
|
|
.string('API Key'),
|
|
baseUrl: z
|
|
.string('Base URL')
|
|
.optional()
|
|
.default('https://api.perplexity.ai/'),
|
|
})
|
|
|
|
type PerplexityConfig = z.input<typeof perplexityConfigSchema>
|
|
|
|
export const providerPerplexityAI = defineProvider<PerplexityConfig, 'perplexity-ai'>({
|
|
id: 'perplexity-ai',
|
|
name: 'Perplexity',
|
|
nameLocalize: ({ t }) => t('settings.pages.providers.provider.perplexity.title'),
|
|
description: 'perplexity.ai',
|
|
descriptionLocalize: ({ t }) => t('settings.pages.providers.provider.perplexity.description'),
|
|
tasks: ['chat'],
|
|
icon: 'i-lobe-icons:perplexity',
|
|
iconColor: 'i-lobe-icons:perplexity-color',
|
|
|
|
createProviderConfig: ({ t }) => perplexityConfigSchema.extend({
|
|
apiKey: perplexityConfigSchema.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: perplexityConfigSchema.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 createPerplexity(config.apiKey, config.baseUrl)
|
|
},
|
|
|
|
validationRequiredWhen(config) {
|
|
return !!config.apiKey?.trim()
|
|
},
|
|
extraMethods: {
|
|
async listModels() {
|
|
return [
|
|
{
|
|
id: 'sonar',
|
|
name: 'Sonar',
|
|
provider: 'perplexity-ai',
|
|
description: 'Lightweight, cost-effective search model with grounding.',
|
|
contextLength: 127072,
|
|
},
|
|
{
|
|
id: 'sonar-pro',
|
|
name: 'Sonar Pro',
|
|
provider: 'perplexity-ai',
|
|
description: 'Advanced search offering with grounding, supporting complex queries and follow-ups.',
|
|
contextLength: 200000,
|
|
},
|
|
{
|
|
id: 'sonar-reasoning-pro',
|
|
name: 'Sonar Reasoning Pro',
|
|
provider: 'perplexity-ai',
|
|
description: 'Precise reasoning offering with Chain of Thought (CoT).',
|
|
contextLength: 127072,
|
|
},
|
|
{
|
|
id: 'sonar-deep-research',
|
|
name: 'Sonar Deep Research',
|
|
provider: 'perplexity-ai',
|
|
description: 'Expert-level research model conducting exhaustive searches and generating comprehensive reports.',
|
|
contextLength: 200000,
|
|
},
|
|
] satisfies ModelInfo[]
|
|
},
|
|
},
|
|
validators: {
|
|
...createOpenAICompatibleValidators({
|
|
checks: [ProviderValidationCheck.Connectivity, ProviderValidationCheck.ChatCompletions],
|
|
}),
|
|
},
|
|
})
|