Merge pull request #6475 from menloresearch/feat/bump-tokenjs

feat: fix remote provider vision capability
This commit is contained in:
Louis 2025-09-22 14:37:26 +07:00 committed by GitHub
parent 8cdb021b3d
commit b0b84b7eda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 94 additions and 54 deletions

View File

@ -82,7 +82,7 @@
"remark-math": "^6.0.0",
"sonner": "^2.0.3",
"tailwindcss": "^4.1.4",
"token.js": "npm:token.js-fork@0.7.23",
"token.js": "npm:token.js-fork@0.7.27",
"tw-animate-css": "^1.2.7",
"ulidx": "^2.4.1",
"unified": "^11.0.5",

View File

@ -15,6 +15,8 @@ import { IconPlus } from '@tabler/icons-react'
import { useState } from 'react'
import { getProviderTitle } from '@/lib/utils'
import { useTranslation } from '@/i18n/react-i18next-compat'
import { ModelCapabilities } from '@/types/models'
import { models as providerModels } from 'token.js'
type DialogAddModelProps = {
provider: ModelProvider
@ -44,7 +46,23 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => {
id: modelId,
model: modelId,
name: modelId,
capabilities: ['completion'], // Default capability
capabilities: [
ModelCapabilities.COMPLETION,
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
].supportsToolCalls as unknown as string[]
).includes(modelId)
? ModelCapabilities.TOOLS
: undefined,
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
].supportsImages as unknown as string[]
).includes(modelId)
? ModelCapabilities.VISION
: undefined,
].filter(Boolean) as string[],
version: '1.0',
}

View File

@ -39,6 +39,13 @@ export class TauriProvidersService extends DefaultProvidersService {
).includes(model)
? ModelCapabilities.TOOLS
: undefined,
(
providerModels[
provider.provider as unknown as keyof typeof providerModels
].supportsImages as unknown as string[]
).includes(model)
? ModelCapabilities.VISION
: undefined,
].filter(Boolean) as string[]
return {
...(modelManifest ?? { id: model, name: model }),
@ -74,8 +81,7 @@ export class TauriProvidersService extends DefaultProvidersService {
}
}) as ProviderSetting[],
models: await Promise.all(
models.map(
async (model) => {
models.map(async (model) => {
let capabilities: string[] = []
// Check for capabilities
@ -89,7 +95,10 @@ export class TauriProvidersService extends DefaultProvidersService {
capabilities = [ModelCapabilities.TOOLS]
}
} catch (error) {
console.warn(`Failed to check tool support for model ${model.id}:`, error)
console.warn(
`Failed to check tool support for model ${model.id}:`,
error
)
// Continue without tool capabilities if check fails
}
}
@ -119,8 +128,7 @@ export class TauriProvidersService extends DefaultProvidersService {
{} as Record<string, ProviderSetting>
),
} as Model
}
)
})
),
}
runtimeProviders.push(provider)
@ -145,7 +153,10 @@ export class TauriProvidersService extends DefaultProvidersService {
// Add Origin header for local providers to avoid CORS issues
// Some local providers (like Ollama) require an Origin header
if (provider.base_url.includes('localhost:') || provider.base_url.includes('127.0.0.1:')) {
if (
provider.base_url.includes('localhost:') ||
provider.base_url.includes('127.0.0.1:')
) {
headers['Origin'] = 'tauri://localhost'
}
@ -187,7 +198,9 @@ export class TauriProvidersService extends DefaultProvidersService {
// Handle different response formats that providers might use
if (data.data && Array.isArray(data.data)) {
// OpenAI format: { data: [{ id: "model-id" }, ...] }
return data.data.map((model: { id: string }) => model.id).filter(Boolean)
return data.data
.map((model: { id: string }) => model.id)
.filter(Boolean)
} else if (Array.isArray(data)) {
// Direct array format: ["model-id1", "model-id2", ...]
return data
@ -214,11 +227,15 @@ export class TauriProvidersService extends DefaultProvidersService {
'Authentication failed',
'Access forbidden',
'Models endpoint not found',
'Failed to fetch models from'
'Failed to fetch models from',
]
if (error instanceof Error &&
structuredErrorPrefixes.some(prefix => (error as Error).message.startsWith(prefix))) {
if (
error instanceof Error &&
structuredErrorPrefixes.some((prefix) =>
(error as Error).message.startsWith(prefix)
)
) {
throw new Error(error.message)
}
@ -236,7 +253,10 @@ export class TauriProvidersService extends DefaultProvidersService {
}
}
async updateSettings(providerName: string, settings: ProviderSetting[]): Promise<void> {
async updateSettings(
providerName: string,
settings: ProviderSetting[]
): Promise<void> {
try {
return ExtensionManager.getInstance()
.getEngine(providerName)

View File

@ -13,4 +13,6 @@ export enum ModelCapabilities {
IMAGE_TO_IMAGE = 'image_to_image',
TEXT_TO_AUDIO = 'text_to_audio',
AUDIO_TO_TEXT = 'audio_to_text',
// Need to consolidate the capabilities list
VISION = 'vision',
}