From 24ff36d424074673a7a2941c5959a254ed666a75 Mon Sep 17 00:00:00 2001 From: Vanalite Date: Thu, 2 Oct 2025 21:48:07 +0700 Subject: [PATCH 1/7] fix: Extract model capabilities correctly for various providers on various platforms --- web-app/src/containers/dialogs/AddModel.tsx | 21 +----- web-app/src/lib/__tests__/models.test.ts | 82 +++++++++++++++++++++ web-app/src/lib/models.ts | 33 +++++++++ web-app/src/services/providers/tauri.ts | 23 +----- web-app/src/services/providers/web.ts | 13 +--- 5 files changed, 123 insertions(+), 49 deletions(-) diff --git a/web-app/src/containers/dialogs/AddModel.tsx b/web-app/src/containers/dialogs/AddModel.tsx index e8fd4e0fd..c44d3a0a5 100644 --- a/web-app/src/containers/dialogs/AddModel.tsx +++ b/web-app/src/containers/dialogs/AddModel.tsx @@ -15,8 +15,7 @@ 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' +import { getModelCapabilities } from '@/lib/models' import { toast } from 'sonner' type DialogAddModelProps = { @@ -52,23 +51,7 @@ export const DialogAddModel = ({ provider, trigger }: DialogAddModelProps) => { id: modelId, model: modelId, name: modelId, - 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[], + capabilities: getModelCapabilities(provider.provider, modelId), version: '1.0', } diff --git a/web-app/src/lib/__tests__/models.test.ts b/web-app/src/lib/__tests__/models.test.ts index 67f37f873..bba4a64a1 100644 --- a/web-app/src/lib/__tests__/models.test.ts +++ b/web-app/src/lib/__tests__/models.test.ts @@ -5,19 +5,30 @@ import { removeYamlFrontMatter, extractModelName, extractModelRepo, + getModelCapabilities, } from '../models' +import { ModelCapabilities } from '@/types/models' // Mock the token.js module vi.mock('token.js', () => ({ models: { openai: { models: ['gpt-3.5-turbo', 'gpt-4'], + supportsToolCalls: ['gpt-3.5-turbo', 'gpt-4'], + supportsImages: ['gpt-4-vision-preview'], }, anthropic: { models: ['claude-3-sonnet', 'claude-3-haiku'], + supportsToolCalls: ['claude-3-sonnet'], + supportsImages: ['claude-3-sonnet', 'claude-3-haiku'], }, mistral: { models: ['mistral-7b', 'mistral-8x7b'], + supportsToolCalls: ['mistral-8x7b'], + }, + // Provider with no capability arrays + cohere: { + models: ['command', 'command-light'], }, }, })) @@ -223,3 +234,74 @@ describe('extractModelRepo', () => { ) }) }) + +describe('getModelCapabilities', () => { + it('returns completion capability for all models', () => { + const capabilities = getModelCapabilities('openai', 'gpt-3.5-turbo') + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + }) + + it('includes tools capability when model supports it', () => { + const capabilities = getModelCapabilities('openai', 'gpt-3.5-turbo') + expect(capabilities).toContain(ModelCapabilities.TOOLS) + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + }) + + it('excludes tools capability when model does not support it', () => { + const capabilities = getModelCapabilities('mistral', 'mistral-7b') + expect(capabilities).not.toContain(ModelCapabilities.TOOLS) + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + }) + + it('includes vision capability when model supports it', () => { + const capabilities = getModelCapabilities('openai', 'gpt-4-vision-preview') + expect(capabilities).toContain(ModelCapabilities.VISION) + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + }) + + it('excludes vision capability when model does not support it', () => { + const capabilities = getModelCapabilities('openai', 'gpt-3.5-turbo') + expect(capabilities).not.toContain(ModelCapabilities.VISION) + }) + + it('includes both tools and vision when model supports both', () => { + const capabilities = getModelCapabilities('anthropic', 'claude-3-sonnet') + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + expect(capabilities).toContain(ModelCapabilities.TOOLS) + expect(capabilities).toContain(ModelCapabilities.VISION) + }) + + it('handles provider with no capability arrays gracefully', () => { + const capabilities = getModelCapabilities('cohere', 'command') + expect(capabilities).toEqual([ModelCapabilities.COMPLETION]) + expect(capabilities).not.toContain(ModelCapabilities.TOOLS) + expect(capabilities).not.toContain(ModelCapabilities.VISION) + }) + + it('handles unknown provider gracefully', () => { + const capabilities = getModelCapabilities('openrouter', 'some-model') + expect(capabilities).toEqual([ModelCapabilities.COMPLETION]) + expect(capabilities).not.toContain(ModelCapabilities.TOOLS) + expect(capabilities).not.toContain(ModelCapabilities.VISION) + }) + + it('handles model not in capability list', () => { + const capabilities = getModelCapabilities('anthropic', 'claude-3-haiku') + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + expect(capabilities).toContain(ModelCapabilities.VISION) + expect(capabilities).not.toContain(ModelCapabilities.TOOLS) + }) + + it('returns only completion for provider with partial capability data', () => { + // Mistral has supportsToolCalls but no supportsImages + const capabilities = getModelCapabilities('mistral', 'mistral-7b') + expect(capabilities).toEqual([ModelCapabilities.COMPLETION]) + }) + + it('handles model that supports tools but not vision', () => { + const capabilities = getModelCapabilities('mistral', 'mistral-8x7b') + expect(capabilities).toContain(ModelCapabilities.COMPLETION) + expect(capabilities).toContain(ModelCapabilities.TOOLS) + expect(capabilities).not.toContain(ModelCapabilities.VISION) + }) +}) diff --git a/web-app/src/lib/models.ts b/web-app/src/lib/models.ts index 0f9b79c40..18d0b6d8e 100644 --- a/web-app/src/lib/models.ts +++ b/web-app/src/lib/models.ts @@ -1,4 +1,5 @@ import { models } from 'token.js' +import { ModelCapabilities } from '@/types/models' export const defaultModel = (provider?: string) => { if (!provider || !Object.keys(models).includes(provider)) { @@ -10,6 +11,38 @@ export const defaultModel = (provider?: string) => { )[0] } +/** + * Determines model capabilities based on provider configuration from token.js + * @param providerName - The provider name (e.g., 'openai', 'anthropic', 'openrouter') + * @param modelId - The model ID to check capabilities for + * @returns Array of model capabilities + */ +export const getModelCapabilities = ( + providerName: string, + modelId: string +): string[] => { + const providerConfig = + models[providerName as unknown as keyof typeof models] + + const supportsToolCalls = Array.isArray( + providerConfig?.supportsToolCalls as unknown + ) + ? (providerConfig.supportsToolCalls as unknown as string[]) + : [] + + const supportsImages = Array.isArray( + providerConfig?.supportsImages as unknown + ) + ? (providerConfig.supportsImages as unknown as string[]) + : [] + + return [ + ModelCapabilities.COMPLETION, + supportsToolCalls.includes(modelId) ? ModelCapabilities.TOOLS : undefined, + supportsImages.includes(modelId) ? ModelCapabilities.VISION : undefined, + ].filter(Boolean) as string[] +} + /** * This utility is to extract cortexso model description from README.md file * @returns diff --git a/web-app/src/services/providers/tauri.ts b/web-app/src/services/providers/tauri.ts index 50f1217da..a8ca36fbb 100644 --- a/web-app/src/services/providers/tauri.ts +++ b/web-app/src/services/providers/tauri.ts @@ -10,6 +10,7 @@ import { modelSettings } from '@/lib/predefined' import { ExtensionManager } from '@/lib/extension' import { fetch as fetchTauri } from '@tauri-apps/plugin-http' import { DefaultProvidersService } from './default' +import { getModelCapabilities } from '@/lib/models' export class TauriProvidersService extends DefaultProvidersService { fetch(): typeof fetch { @@ -26,32 +27,16 @@ export class TauriProvidersService extends DefaultProvidersService { provider.provider as unknown as keyof typeof providerModels ].models as unknown as string[] - if (Array.isArray(builtInModels)) + if (Array.isArray(builtInModels)) { models = builtInModels.map((model) => { const modelManifest = models.find((e) => e.id === model) // TODO: Check chat_template for tool call support - const capabilities = [ - ModelCapabilities.COMPLETION, - ( - providerModels[ - provider.provider as unknown as keyof typeof providerModels - ]?.supportsToolCalls as unknown as string[] - )?.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 }), - capabilities, + capabilities: getModelCapabilities(provider.provider, model), } as Model }) + } } return { diff --git a/web-app/src/services/providers/web.ts b/web-app/src/services/providers/web.ts index 6a7865be8..29d4a9cb7 100644 --- a/web-app/src/services/providers/web.ts +++ b/web-app/src/services/providers/web.ts @@ -11,6 +11,7 @@ import { ExtensionManager } from '@/lib/extension' import type { ProvidersService } from './types' import { PlatformFeatures } from '@/lib/platform/const' import { PlatformFeature } from '@/lib/platform/types' +import { getModelCapabilities } from '@/lib/models' export class WebProvidersService implements ProvidersService { async getProviders(): Promise { @@ -88,19 +89,9 @@ export class WebProvidersService implements ProvidersService { models = builtInModels.map((model) => { const modelManifest = models.find((e) => e.id === model) // TODO: Check chat_template for tool call support - const capabilities = [ - ModelCapabilities.COMPLETION, - ( - providerModels[ - provider.provider as unknown as keyof typeof providerModels - ]?.supportsToolCalls as unknown as string[] - )?.includes(model) - ? ModelCapabilities.TOOLS - : undefined, - ].filter(Boolean) as string[] return { ...(modelManifest ?? { id: model, name: model }), - capabilities, + capabilities: getModelCapabilities(provider.provider, model), } as Model }) } From c4af638a17a6105011bfb46ae4d0112dc3ae164b Mon Sep 17 00:00:00 2001 From: Minh141120 Date: Fri, 3 Oct 2025 11:56:31 +0700 Subject: [PATCH 2/7] ci: remove upload msi --- .github/workflows/template-tauri-build-windows-x64.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/template-tauri-build-windows-x64.yml b/.github/workflows/template-tauri-build-windows-x64.yml index ed00ef90f..963bb144c 100644 --- a/.github/workflows/template-tauri-build-windows-x64.yml +++ b/.github/workflows/template-tauri-build-windows-x64.yml @@ -234,8 +234,6 @@ jobs: # Upload for tauri updater aws s3 cp ./${{ steps.metadata.outputs.FILE_NAME }} s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-${{ inputs.channel }}/${{ steps.metadata.outputs.FILE_NAME }} aws s3 cp ./${{ steps.metadata.outputs.FILE_NAME }}.sig s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-${{ inputs.channel }}/${{ steps.metadata.outputs.FILE_NAME }}.sig - - aws s3 cp ./src-tauri/target/release/bundle/msi/${{ steps.metadata.outputs.MSI_FILE_NAME }} s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-${{ inputs.channel }}/${{ steps.metadata.outputs.MSI_FILE_NAME }} env: AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} From 5adaf6297538919bcf7125cca15f4274d2d49702 Mon Sep 17 00:00:00 2001 From: Dinh Long Nguyen Date: Fri, 3 Oct 2025 13:54:37 +0700 Subject: [PATCH 3/7] fix: extensions missing on Unix dev (#6724) * fix: extensions missing on Unix dev * re add bun uv for mcp --- src-tauri/tauri.linux.conf.json | 3 ++- src-tauri/tauri.macos.conf.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src-tauri/tauri.linux.conf.json b/src-tauri/tauri.linux.conf.json index 85f39ba50..02fa8cdf6 100644 --- a/src-tauri/tauri.linux.conf.json +++ b/src-tauri/tauri.linux.conf.json @@ -6,7 +6,8 @@ }, "bundle": { "targets": ["deb", "appimage"], - "resources": ["resources/LICENSE"], + "resources": ["resources/pre-install/**/*", "resources/LICENSE"], + "externalBin": ["resources/bin/uv"], "linux": { "appimage": { "bundleMediaFramework": false, diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json index 2113bd0fa..92f937f0f 100644 --- a/src-tauri/tauri.macos.conf.json +++ b/src-tauri/tauri.macos.conf.json @@ -6,6 +6,7 @@ }, "bundle": { "targets": ["app", "dmg"], - "resources": ["resources/LICENSE"] + "resources": ["resources/pre-install/**/*", "resources/LICENSE"], + "externalBin": ["resources/bin/bun", "resources/bin/uv"] } } From cef351bfd0803bc539f76694402eed69f9e8cba2 Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 3 Oct 2025 14:12:16 +0700 Subject: [PATCH 4/7] fix: Local API Server - disable settings on run (#6707) --- web-app/src/routes/settings/local-api-server.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-app/src/routes/settings/local-api-server.tsx b/web-app/src/routes/settings/local-api-server.tsx index 3628a6f8c..b3360e98e 100644 --- a/web-app/src/routes/settings/local-api-server.tsx +++ b/web-app/src/routes/settings/local-api-server.tsx @@ -258,7 +258,7 @@ function LocalAPIServerContent() { } } - const isServerRunning = serverStatus === 'running' + const isServerRunning = serverStatus !== 'stopped' return (
From 8b448d1c0b6bfc9d435b9b0d2413eaa65ad8ef89 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Fri, 3 Oct 2025 23:17:54 +0700 Subject: [PATCH 5/7] changelog: release 0.7.1 --- .../changelog/2025-10-02-jan-projects.mdx | 2 +- .../2025-10-03-jan-stability-improvements.mdx | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx diff --git a/docs/src/pages/changelog/2025-10-02-jan-projects.mdx b/docs/src/pages/changelog/2025-10-02-jan-projects.mdx index 63f29194d..851e26403 100644 --- a/docs/src/pages/changelog/2025-10-02-jan-projects.mdx +++ b/docs/src/pages/changelog/2025-10-02-jan-projects.mdx @@ -1,6 +1,6 @@ --- title: "Jan v0.7.0: Jan Projects" -version: v0.7.0 +version: 0.7.0 description: "Jan v0.7.0 introduces Projects, model renaming, llama.cpp auto-tuning, model stats, and Azure support." date: 2025-10-02 ogImage: "/assets/images/changelog/jan-release-v0.7.0.jpeg" diff --git a/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx b/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx new file mode 100644 index 000000000..5fa69d98c --- /dev/null +++ b/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx @@ -0,0 +1,28 @@ +--- +title: "Jan v0.7.1: Fixes Windows Version Revert & OpenRouter Models" +version: 0.7.1 +description: "Jan v0.7.1 focuses on bug fixes, including a windows version revert and improvements to OpenRouter models." +date: 2025-10-03 +--- + +import ChangelogHeader from "@/components/Changelog/ChangelogHeader" +import { Callout } from 'nextra/components' + + + +## Jan v0.7.1: Bug Fixes: Version Revert & OpenRouter Models + +Jan v0.7.0 is live! This release focuses on helping you organize your workspace and better understand how models run. + +### Two quick fixes: +- Jan no longer reverts to an older version on load +- OpenRouter can now add models again +- Add headers for anthropic request to fetch models + +--- + +Update your Jan or [download the latest version](https://jan.ai/). + +For the complete list of changes, see the [GitHub release notes](https://github.com/janhq/jan/releases/tag/v0.7.1). + + From e346b293f671b533a4117c7610876a6cf27ef779 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Fri, 3 Oct 2025 23:23:46 +0700 Subject: [PATCH 6/7] chore: wrong version in detail changelog --- .../pages/changelog/2025-10-03-jan-stability-improvements.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx b/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx index 5fa69d98c..b2379c7cb 100644 --- a/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx +++ b/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx @@ -10,9 +10,9 @@ import { Callout } from 'nextra/components' -## Jan v0.7.1: Bug Fixes: Version Revert & OpenRouter Models +## Bug Fixes: Windows Version Revert & OpenRouter Models -Jan v0.7.0 is live! This release focuses on helping you organize your workspace and better understand how models run. +Jan v0.7.1 is live! This release focuses on helping you organize your workspace and better understand how models run. ### Two quick fixes: - Jan no longer reverts to an older version on load From ca485b4a35b0a8f405b4f27567a17186e01a65b7 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Fri, 3 Oct 2025 23:33:02 +0700 Subject: [PATCH 7/7] fix: update detail changelog 0.7.1 --- .../changelog/2025-10-03-jan-stability-improvements.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx b/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx index b2379c7cb..df756ccfc 100644 --- a/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx +++ b/docs/src/pages/changelog/2025-10-03-jan-stability-improvements.mdx @@ -10,11 +10,9 @@ import { Callout } from 'nextra/components' -## Bug Fixes: Windows Version Revert & OpenRouter Models +### Bug Fixes: Windows Version Revert & OpenRouter Models -Jan v0.7.1 is live! This release focuses on helping you organize your workspace and better understand how models run. - -### Two quick fixes: +#### Two quick fixes: - Jan no longer reverts to an older version on load - OpenRouter can now add models again - Add headers for anthropic request to fetch models