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", "remark-math": "^6.0.0",
"sonner": "^2.0.3", "sonner": "^2.0.3",
"tailwindcss": "^4.1.4", "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", "tw-animate-css": "^1.2.7",
"ulidx": "^2.4.1", "ulidx": "^2.4.1",
"unified": "^11.0.5", "unified": "^11.0.5",

View File

@ -15,6 +15,8 @@ import { IconPlus } from '@tabler/icons-react'
import { useState } from 'react' import { useState } from 'react'
import { getProviderTitle } from '@/lib/utils' import { getProviderTitle } from '@/lib/utils'
import { useTranslation } from '@/i18n/react-i18next-compat' import { useTranslation } from '@/i18n/react-i18next-compat'
import { ModelCapabilities } from '@/types/models'
import { models as providerModels } from 'token.js'
type DialogAddModelProps = { type DialogAddModelProps = {
provider: ModelProvider provider: ModelProvider
@ -44,7 +46,23 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => {
id: modelId, id: modelId,
model: modelId, model: modelId,
name: 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', version: '1.0',
} }

View File

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

View File

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