fix: engine version update - cortex version bump - update tests (#4787)

This commit is contained in:
Louis 2025-03-10 13:26:48 +07:00 committed by GitHub
parent 77717a780e
commit 455d320d35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 133 additions and 77 deletions

View File

@ -11,9 +11,11 @@ export default defineConfig([
}, },
define: { define: {
NODE: JSON.stringify(`${pkgJson.name}/${pkgJson.node}`), NODE: JSON.stringify(`${pkgJson.name}/${pkgJson.node}`),
API_URL: JSON.stringify(`http://127.0.0.1:${process.env.CORTEX_API_PORT ?? "39291"}`), API_URL: JSON.stringify(
`http://127.0.0.1:${process.env.CORTEX_API_PORT ?? '39291'}`
),
PLATFORM: JSON.stringify(process.platform), PLATFORM: JSON.stringify(process.platform),
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.49'), CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.54'),
DEFAULT_REMOTE_ENGINES: JSON.stringify(engines), DEFAULT_REMOTE_ENGINES: JSON.stringify(engines),
DEFAULT_REMOTE_MODELS: JSON.stringify(models), DEFAULT_REMOTE_MODELS: JSON.stringify(models),
DEFAULT_REQUEST_PAYLOAD_TRANSFORM: JSON.stringify( DEFAULT_REQUEST_PAYLOAD_TRANSFORM: JSON.stringify(
@ -36,7 +38,7 @@ export default defineConfig([
file: 'dist/node/index.cjs.js', file: 'dist/node/index.cjs.js',
}, },
define: { define: {
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.49'), CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.54'),
}, },
}, },
]) ])

View File

@ -286,7 +286,7 @@ export default class JanEngineManagementExtension extends EngineManagementExtens
if ( if (
!installedEngines.some( !installedEngines.some(
(e) => e.name === variant.variant && e.version === variant.version (e) => e.name === variant.variant && e.version === variant.version
) ) || variant.version < CORTEX_ENGINE_VERSION
) { ) {
throw new EngineError( throw new EngineError(
'Default engine is not available, use bundled version.' 'Default engine is not available, use bundled version.'

View File

@ -1,8 +1,4 @@
import { import { HardwareManagementExtension, HardwareInformation } from '@janhq/core'
executeOnMain,
HardwareManagementExtension,
HardwareInformation,
} from '@janhq/core'
import ky from 'ky' import ky from 'ky'
import PQueue from 'p-queue' import PQueue from 'p-queue'

View File

@ -1 +1 @@
1.0.11-rc6 1.0.11-rc7

View File

@ -2,7 +2,7 @@
set BIN_PATH=./bin set BIN_PATH=./bin
set SHARED_PATH=./../../electron/shared set SHARED_PATH=./../../electron/shared
set /p CORTEX_VERSION=<./bin/version.txt set /p CORTEX_VERSION=<./bin/version.txt
set ENGINE_VERSION=0.1.49 set ENGINE_VERSION=0.1.54
@REM Download cortex.llamacpp binaries @REM Download cortex.llamacpp binaries
set DOWNLOAD_URL=https://github.com/janhq/cortex.llamacpp/releases/download/v%ENGINE_VERSION%/cortex.llamacpp-%ENGINE_VERSION%-windows-amd64 set DOWNLOAD_URL=https://github.com/janhq/cortex.llamacpp/releases/download/v%ENGINE_VERSION%/cortex.llamacpp-%ENGINE_VERSION%-windows-amd64

View File

@ -2,7 +2,7 @@
# Read CORTEX_VERSION # Read CORTEX_VERSION
CORTEX_VERSION=$(cat ./bin/version.txt) CORTEX_VERSION=$(cat ./bin/version.txt)
ENGINE_VERSION=0.1.49 ENGINE_VERSION=0.1.54
CORTEX_RELEASE_URL="https://github.com/janhq/cortex.cpp/releases/download" CORTEX_RELEASE_URL="https://github.com/janhq/cortex.cpp/releases/download"
ENGINE_DOWNLOAD_URL="https://github.com/janhq/cortex.llamacpp/releases/download/v${ENGINE_VERSION}/cortex.llamacpp-${ENGINE_VERSION}" ENGINE_DOWNLOAD_URL="https://github.com/janhq/cortex.llamacpp/releases/download/v${ENGINE_VERSION}/cortex.llamacpp-${ENGINE_VERSION}"
CUDA_DOWNLOAD_URL="https://github.com/janhq/cortex.llamacpp/releases/download/v${ENGINE_VERSION}" CUDA_DOWNLOAD_URL="https://github.com/janhq/cortex.llamacpp/releases/download/v${ENGINE_VERSION}"

View File

@ -1,5 +0,0 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};

View File

@ -8,7 +8,7 @@
"author": "Jan <service@jan.ai>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"test": "jest", "test": "vitest run",
"build": "rolldown -c rolldown.config.mjs", "build": "rolldown -c rolldown.config.mjs",
"downloadcortex:linux:darwin": "./download.sh", "downloadcortex:linux:darwin": "./download.sh",
"downloadcortex:win32": "download.bat", "downloadcortex:win32": "download.bat",
@ -35,17 +35,15 @@
"rolldown": "1.0.0-beta.1", "rolldown": "1.0.0-beta.1",
"run-script-os": "^1.1.6", "run-script-os": "^1.1.6",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"typescript": "^5.3.3" "typescript": "^5.3.3",
"vitest": "^3.0.8"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "../../core/package.tgz", "@janhq/core": "../../core/package.tgz",
"decompress": "^4.2.1",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ky": "^1.7.2", "ky": "^1.7.2",
"p-queue": "^8.0.1", "p-queue": "^8.0.1",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"tcp-port-used": "^1.0.2",
"terminate": "2.6.1",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
"engines": { "engines": {

View File

@ -13,9 +13,13 @@ export default defineConfig([
define: { define: {
NODE: JSON.stringify(`${packageJson.name}/${packageJson.node}`), NODE: JSON.stringify(`${packageJson.name}/${packageJson.node}`),
SETTINGS: JSON.stringify(defaultSettingJson), SETTINGS: JSON.stringify(defaultSettingJson),
CORTEX_API_URL: JSON.stringify(`http://127.0.0.1:${process.env.CORTEX_API_PORT ?? "39291"}`), CORTEX_API_URL: JSON.stringify(
CORTEX_SOCKET_URL: JSON.stringify(`ws://127.0.0.1:${process.env.CORTEX_API_PORT ?? "39291"}`), `http://127.0.0.1:${process.env.CORTEX_API_PORT ?? '39291'}`
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.49'), ),
CORTEX_SOCKET_URL: JSON.stringify(
`ws://127.0.0.1:${process.env.CORTEX_API_PORT ?? '39291'}`
),
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.54'),
}, },
}, },
{ {
@ -31,7 +35,9 @@ export default defineConfig([
extensions: ['.js', '.ts', '.json'], extensions: ['.js', '.ts', '.json'],
}, },
define: { define: {
CORTEX_API_URL: JSON.stringify(`http://127.0.0.1:${process.env.CORTEX_API_PORT ?? "39291"}`), CORTEX_API_URL: JSON.stringify(
`http://127.0.0.1:${process.env.CORTEX_API_PORT ?? '39291'}`
),
}, },
platform: 'node', platform: 'node',
}, },

View File

@ -10,15 +10,11 @@ import {
Model, Model,
executeOnMain, executeOnMain,
EngineEvent, EngineEvent,
joinPath,
LocalOAIEngine, LocalOAIEngine,
InferenceEngine, InferenceEngine,
getJanDataFolderPath,
extractModelLoadParams, extractModelLoadParams,
fs,
events, events,
ModelEvent, ModelEvent,
dirName,
} from '@janhq/core' } from '@janhq/core'
import PQueue from 'p-queue' import PQueue from 'p-queue'
import ky from 'ky' import ky from 'ky'

View File

@ -1,6 +1,14 @@
jest.mock('@janhq/core/node', () => ({ import { describe, it, expect, vi } from 'vitest'
...jest.requireActual('@janhq/core/node'), // Mocks
const CORTEX_API_URL = 'http://localhost:3000'
vi.stubGlobal('CORTEX_API_URL', CORTEX_API_URL)
vi.mock('@janhq/core/node', (actual) => ({
...actual(),
getJanDataFolderPath: () => '', getJanDataFolderPath: () => '',
appResourcePath: () => '/mock/path',
log: vi.fn(),
getSystemResourceInfo: () => { getSystemResourceInfo: () => {
return { return {
cpu: { cpu: {
@ -30,25 +38,36 @@ jest.mock('@janhq/core/node', () => ({
}, },
})) }))
jest.mock('fs', () => ({ vi.mock('fs', () => ({
default: { default: {
readdirSync: () => [], readdirSync: () => [],
}, },
})) }))
jest.mock('child_process', () => ({ vi.mock('./watchdog', () => {
return {
ProcessWatchdog: vi.fn().mockImplementation(() => {
return {
start: vi.fn(),
terminate: vi.fn(),
}
}),
}
})
vi.mock('child_process', () => ({
exec: () => { exec: () => {
return { return {
stdout: { on: jest.fn() }, stdout: { on: vi.fn() },
stderr: { on: jest.fn() }, stderr: { on: vi.fn() },
on: jest.fn(), on: vi.fn(),
} }
}, },
spawn: () => { spawn: () => {
return { return {
stdout: { on: jest.fn() }, stdout: { on: vi.fn() },
stderr: { on: jest.fn() }, stderr: { on: vi.fn() },
on: jest.fn(), on: vi.fn(),
pid: '111', pid: '111',
} }
}, },
@ -56,28 +75,70 @@ jest.mock('child_process', () => ({
import index from './index' import index from './index'
describe('dispose', () => { describe('Cortex extension node interface', () => {
it('should dispose a model successfully on Mac', async () => { describe('run', () => {
Object.defineProperty(process, 'platform', { it('should start the cortex subprocess on macOS', async () => {
value: 'darwin', Object.defineProperty(process, 'platform', {
value: 'darwin',
})
const result = await index.run()
expect(result).toBeUndefined()
}) })
// Call the dispose function it('should start the cortex subprocess on Windows', async () => {
const result = await index.dispose() Object.defineProperty(process, 'platform', {
value: 'win32',
})
// Assert that the result is as expected const result = await index.run()
expect(result).toBeUndefined() expect(result).toBeUndefined()
})
it('should set the proper environment variables based on platform', async () => {
// Test for Windows
Object.defineProperty(process, 'platform', {
value: 'win32',
})
process.env.PATH = '/original/path'
await index.run()
expect(process.env.PATH).toContain('/original/path')
// Test for non-Windows (macOS/Linux)
Object.defineProperty(process, 'platform', {
value: 'darwin',
})
process.env.LD_LIBRARY_PATH = '/original/ld/path'
await index.run()
expect(process.env.LD_LIBRARY_PATH).toContain('/original/ld/path')
})
}) })
it('should kill the subprocess successfully on Windows', async () => { describe('dispose', () => {
Object.defineProperty(process, 'platform', { it('should dispose a model successfully on Mac', async () => {
value: 'win32', Object.defineProperty(process, 'platform', {
value: 'darwin',
})
// Call the dispose function
const result = index.dispose()
// Assert that the result is as expected
expect(result).toBeUndefined()
}) })
// Call the killSubprocess function it('should kill the subprocess successfully on Windows', async () => {
const result = await index.dispose() Object.defineProperty(process, 'platform', {
value: 'win32',
})
// Assert that the result is as expected // Call the dispose function
expect(result).toBeUndefined() const result = index.dispose()
// Assert that the result is as expected
expect(result).toBeUndefined()
})
}) })
}) })

View File

@ -1,13 +1,7 @@
import path from 'path' import path from 'path'
import { import { appResourcePath, getJanDataFolderPath, log } from '@janhq/core/node'
appResourcePath,
getJanDataFolderPath,
log,
} from '@janhq/core/node'
import { ProcessWatchdog } from './watchdog' import { ProcessWatchdog } from './watchdog'
// The HOST address to use for the Nitro subprocess
const LOCAL_PORT = CORTEX_API_URL.split(":").pop() ?? "39291"
let watchdog: ProcessWatchdog | undefined = undefined let watchdog: ProcessWatchdog | undefined = undefined
/** /**
@ -37,6 +31,9 @@ function run(): Promise<any> {
watchdog.terminate() watchdog.terminate()
} }
// The HOST address to use for the cortex subprocess
const LOCAL_PORT = CORTEX_API_URL.split(':').pop() ?? '39291'
watchdog = new ProcessWatchdog( watchdog = new ProcessWatchdog(
executablePath, executablePath,
[ [

View File

@ -67,13 +67,18 @@ const LocalEngineSettings = ({ engine }: { engine: InferenceEngine }) => {
RecommendEngineVariantAtom RecommendEngineVariantAtom
) )
const isEngineUpdated = const isEngineUpdated = useMemo(() => {
latestReleasedEngine && if (!latestReleasedEngine || !defaultEngineVariant) return false
latestReleasedEngine.some((item) => const latestVariant = latestReleasedEngine.find((item) =>
item.name.includes( item.name.includes(defaultEngineVariant.variant)
defaultEngineVariant?.version.replace(/^v/, '') as string
)
) )
if (!latestVariant) return false
const latestVersion = latestVariant.name
.replace(defaultEngineVariant.variant, '')
.replaceAll('-', '')
const currentVersion = defaultEngineVariant.version.replace(/^v/, '')
return latestVersion <= currentVersion
}, [latestReleasedEngine, defaultEngineVariant])
const availableVariants = useMemo( const availableVariants = useMemo(
() => () =>

View File

@ -170,7 +170,7 @@ const ChatInput = () => {
!!fileUpload || !!fileUpload ||
(activeAssistant?.tools && (activeAssistant?.tools &&
!activeAssistant?.tools[0]?.enabled && !activeAssistant?.tools[0]?.enabled &&
!activeAssistant?.model.settings?.vision_model) !activeAssistant?.model.settings?.mmproj)
) { ) {
e.stopPropagation() e.stopPropagation()
} else { } else {
@ -193,7 +193,7 @@ const ChatInput = () => {
{!!fileUpload || {!!fileUpload ||
(activeAssistant?.tools && (activeAssistant?.tools &&
!activeAssistant?.tools[0]?.enabled && !activeAssistant?.tools[0]?.enabled &&
!activeAssistant?.model.settings?.vision_model && ( !activeAssistant?.model.settings?.mmproj && (
<> <>
{!!fileUpload && ( {!!fileUpload && (
<span> <span>
@ -231,13 +231,13 @@ const ChatInput = () => {
<li <li
className={twMerge( className={twMerge(
'text-[hsla(var(--text-secondary)] hover:bg-secondary flex w-full items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]', 'text-[hsla(var(--text-secondary)] hover:bg-secondary flex w-full items-center space-x-2 px-4 py-2 hover:bg-[hsla(var(--dropdown-menu-hover-bg))]',
activeAssistant?.model.settings?.vision_model && activeAssistant?.model.settings?.mmproj &&
isModelSupportRagAndTools isModelSupportRagAndTools
? 'cursor-pointer' ? 'cursor-pointer'
: 'cursor-not-allowed opacity-50' : 'cursor-not-allowed opacity-50'
)} )}
onClick={() => { onClick={() => {
if (activeAssistant?.model.settings?.vision_model) { if (activeAssistant?.model.settings?.mmproj) {
imageInputRef.current?.click() imageInputRef.current?.click()
setShowAttachmentMenus(false) setShowAttachmentMenus(false)
} }

View File

@ -61,7 +61,7 @@ const ThreadCenterPanel = () => {
const activeAssistant = useAtomValue(activeAssistantAtom) const activeAssistant = useAtomValue(activeAssistantAtom)
const chatWidth = useAtomValue(chatWidthAtom) const chatWidth = useAtomValue(chatWidthAtom)
const upload = uploader() const upload = uploader()
const acceptedFormat: Accept = activeAssistant?.model.settings?.vision_model const acceptedFormat: Accept = activeAssistant?.model.settings?.mmproj
? { ? {
'application/pdf': ['.pdf'], 'application/pdf': ['.pdf'],
'image/jpeg': ['.jpeg'], 'image/jpeg': ['.jpeg'],
@ -83,7 +83,7 @@ const ThreadCenterPanel = () => {
if ( if (
e.dataTransfer.items.length === 1 && e.dataTransfer.items.length === 1 &&
((activeAssistant?.tools && activeAssistant?.tools[0]?.enabled) || ((activeAssistant?.tools && activeAssistant?.tools[0]?.enabled) ||
activeAssistant?.model.settings?.vision_model) activeAssistant?.model.settings?.mmproj)
) { ) {
setDragOver(true) setDragOver(true)
} else if ( } else if (
@ -105,7 +105,7 @@ const ThreadCenterPanel = () => {
rejectFiles.length !== 0 || rejectFiles.length !== 0 ||
(activeAssistant?.tools && (activeAssistant?.tools &&
!activeAssistant?.tools[0]?.enabled && !activeAssistant?.tools[0]?.enabled &&
!activeAssistant?.model.settings?.vision_model) !activeAssistant?.model.settings?.mmproj)
) )
return return
const imageType = files[0]?.type.includes('image') const imageType = files[0]?.type.includes('image')
@ -182,7 +182,7 @@ const ThreadCenterPanel = () => {
<h6 className="font-bold"> <h6 className="font-bold">
{isDragReject {isDragReject
? `Currently, we only support 1 attachment at the same time with ${ ? `Currently, we only support 1 attachment at the same time with ${
activeAssistant?.model.settings?.vision_model activeAssistant?.model.settings?.mmproj
? 'PDF, JPEG, JPG, PNG' ? 'PDF, JPEG, JPG, PNG'
: 'PDF' : 'PDF'
} format` } format`
@ -190,7 +190,7 @@ const ThreadCenterPanel = () => {
</h6> </h6>
{!isDragReject && ( {!isDragReject && (
<p className="mt-2"> <p className="mt-2">
{activeAssistant?.model.settings?.vision_model {activeAssistant?.model.settings?.mmproj
? 'PDF, JPEG, JPG, PNG' ? 'PDF, JPEG, JPG, PNG'
: 'PDF'} : 'PDF'}
</p> </p>