Merge branch 'dev' of https://github.com/janhq/jan into dev

This commit is contained in:
Ashley 2025-01-01 23:49:06 +07:00
commit b2ab5423df
156 changed files with 30359 additions and 1946 deletions

View File

@ -44,16 +44,17 @@ jobs:
- uses: actions/checkout@v3
with:
ref: ${{ github.base_ref }}
- name: Use Node.js v20.9.0
- name: Use Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: v20.9.0
node-version: 20
- name: Install dependencies
run: |
make config-yarn
yarn
yarn build:core
yarn build:joi
yarn build:core
- name: Run test coverage
run: yarn test:coverage
@ -66,7 +67,7 @@ jobs:
test-on-macos:
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
runs-on: [self-hosted, macOS, macos-desktop]
runs-on: macos-latest
steps:
- name: Getting the repo
uses: actions/checkout@v3
@ -78,6 +79,10 @@ jobs:
with:
node-version: 20
- name: Set IS_TEST environment variable
run: |
echo "IS_TEST=true" >> $GITHUB_ENV
- name: 'Cleanup cache'
continue-on-error: true
run: |
@ -100,18 +105,13 @@ jobs:
- name: Linter and test
run: |
npm config set registry ${{ secrets.NPM_PROXY }} --global
yarn config set registry ${{ secrets.NPM_PROXY }} --global
make test
env:
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
# TURBO_API: '${{ secrets.TURBO_API }}'
# TURBO_TEAM: 'macos'
# TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
test-on-macos-pr-target:
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
runs-on: [self-hosted, macOS, macos-desktop]
runs-on: macos-latest
steps:
- name: Getting the repo
uses: actions/checkout@v3
@ -131,8 +131,6 @@ jobs:
- name: Linter and test
run: |
npm config set registry https://registry.npmjs.org --global
yarn config set registry https://registry.npmjs.org --global
make test
env:
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
@ -182,13 +180,8 @@ jobs:
- name: Linter and test
shell: powershell
run: |
npm config set registry ${{ secrets.NPM_PROXY }} --global
yarn config set registry ${{ secrets.NPM_PROXY }} --global
make test
# env:
# TURBO_API: '${{ secrets.TURBO_API }}'
# TURBO_TEAM: 'windows'
# TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
test-on-windows-pr:
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
runs-on: windows-desktop-default-windows-security
@ -199,7 +192,7 @@ jobs:
fetch-depth: 0
- name: Installing node
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: 20
@ -230,17 +223,11 @@ jobs:
- name: Linter and test
shell: powershell
run: |
npm config set registry ${{ secrets.NPM_PROXY }} --global
yarn config set registry ${{ secrets.NPM_PROXY }} --global
make test
# env:
# TURBO_API: '${{ secrets.TURBO_API }}'
# TURBO_TEAM: 'windows'
# TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
test-on-windows-pr-target:
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
runs-on: windows-desktop-default-windows-security
runs-on: windows-latest
steps:
- name: Getting the repo
uses: actions/checkout@v3
@ -268,12 +255,10 @@ jobs:
- name: Linter and test
shell: powershell
run: |
npm config set registry https://registry.npmjs.org --global
yarn config set registry https://registry.npmjs.org --global
make test
test-on-ubuntu:
runs-on: [self-hosted, Linux, ubuntu-desktop]
runs-on: ubuntu-latest
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
- name: Getting the repo
@ -311,13 +296,7 @@ jobs:
run: |
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
echo -e "Display ID: $DISPLAY"
npm config set registry ${{ secrets.NPM_PROXY }} --global
yarn config set registry ${{ secrets.NPM_PROXY }} --global
make test
# env:
# TURBO_API: '${{ secrets.TURBO_API }}'
# TURBO_TEAM: 'linux'
# TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
- uses: actions/upload-artifact@v4
if: always()
@ -327,7 +306,7 @@ jobs:
retention-days: 2
coverage-check:
runs-on: [self-hosted, Linux, ubuntu-desktop]
runs-on: ubuntu-latest
needs: base_branch_cov
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
@ -341,6 +320,9 @@ jobs:
with:
node-version: 20
- name: Install yarn
run: npm install -g yarn
- name: 'Cleanup cache'
continue-on-error: true
run: |
@ -356,15 +338,9 @@ jobs:
run: |
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
echo -e "Display ID: $DISPLAY"
npm config set registry ${{ secrets.NPM_PROXY }} --global
yarn config set registry ${{ secrets.NPM_PROXY }} --global
make lint
yarn build:test
yarn test:coverage
# env:
# TURBO_API: '${{ secrets.TURBO_API }}'
# TURBO_TEAM: 'linux'
# TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'
- name: Generate Code Coverage report
id: code-coverage
@ -377,7 +353,7 @@ jobs:
show-annotations: 'warning'
test-on-ubuntu-pr-target:
runs-on: [self-hosted, Linux, ubuntu-desktop]
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
steps:
- name: Getting the repo
@ -400,6 +376,4 @@ jobs:
run: |
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
echo -e "Display ID: $DISPLAY"
npm config set registry https://registry.npmjs.org --global
yarn config set registry https://registry.npmjs.org --global
make test

View File

@ -1,4 +1,4 @@
name: Publish plugin models Package to npmjs
name: Publish core Package to npmjs
on:
push:
tags: ["v[0-9]+.[0-9]+.[0-9]+-core"]
@ -45,7 +45,7 @@ jobs:
node-version: "20.x"
registry-url: "https://registry.npmjs.org"
- run: cd core && yarn install && yarn build
- run: cd core && corepack enable && corepack prepare yarn@4.5.3 --activate && yarn --version && yarn install && yarn build
- run: cd core && yarn publish --access public
if: github.event_name == 'push'

View File

@ -1,4 +1,4 @@
name: Publish plugin models Package to npmjs
name: Publish joi Package to npmjs
on:
push:
tags: ["v[0-9]+.[0-9]+.[0-9]+-joi"]
@ -45,7 +45,7 @@ jobs:
node-version: "20.x"
registry-url: "https://registry.npmjs.org"
- run: cd joi && yarn install && yarn build
- run: cd joi && corepack enable && corepack prepare yarn@4.5.3 --activate && yarn --version && yarn install && yarn build
- run: cd joi && yarn publish --access public
if: github.event_name == 'push'

5
.gitignore vendored
View File

@ -8,7 +8,6 @@ error.log
node_modules
*.tgz
!charts/server/charts/*.tgz
yarn.lock
dist
build
.DS_Store
@ -48,3 +47,7 @@ coverage
test_results.html
*.tsbuildinfo
electron/shared/**
# docs
docs/yarn.lock
electron/.version.bak

3
.yarnrc.yml Normal file
View File

@ -0,0 +1,3 @@
nmHoistingLimits: workspaces
nodeLinker: node-modules
checksumBehavior: update

View File

@ -10,23 +10,23 @@ REPORT_PORTAL_DESCRIPTION ?= "Jan App report"
all:
@echo "Specify a target to run"
# Builds the UI kit
build-joi:
ifeq ($(OS),Windows_NT)
cd joi && yarn config set network-timeout 300000 && yarn install && yarn build
else
cd joi && yarn install && yarn build
endif
# Config yarn version
config-yarn:
corepack enable
corepack prepare yarn@4.5.3 --activate
yarn --version
yarn config set -H enableImmutableInstalls false
# Installs yarn dependencies and builds core and extensions
install-and-build: build-joi
install-and-build: config-yarn
ifeq ($(OS),Windows_NT)
yarn config set network-timeout 300000
echo "skip"
endif
yarn global add turbo@1.13.2
yarn install
yarn build:joi
yarn build:core
yarn build:server
yarn install
yarn build:extensions
check-file-counts: install-and-build
@ -117,9 +117,8 @@ build: check-file-counts
clean:
ifeq ($(OS),Windows_NT)
-powershell -Command "Get-ChildItem -Path . -Include node_modules, .next, dist, build, out, .turbo -Recurse -Directory | Remove-Item -Recurse -Force"
-powershell -Command "Get-ChildItem -Path . -Include package-lock.json -Recurse -File | Remove-Item -Recurse -Force"
-powershell -Command "Get-ChildItem -Path . -Include yarn.lock -Recurse -File | Remove-Item -Recurse -Force"
-powershell -Command "Get-ChildItem -Path . -Include node_modules, .next, dist, build, out, .turbo, .yarn -Recurse -Directory | Remove-Item -Recurse -Force"
-powershell -Command "Get-ChildItem -Path . -Include package-lock.json, tsconfig.tsbuildinfo -Recurse -File | Remove-Item -Recurse -Force"
-powershell -Command "Remove-Item -Recurse -Force ./pre-install/*.tgz"
-powershell -Command "Remove-Item -Recurse -Force ./extensions/*/*.tgz"
-powershell -Command "Remove-Item -Recurse -Force ./electron/pre-install/*.tgz"
@ -131,8 +130,8 @@ else ifeq ($(shell uname -s),Linux)
find . -name "build" -type d -exec rm -rf '{}' +
find . -name "out" -type d -exec rm -rf '{}' +
find . -name ".turbo" -type d -exec rm -rf '{}' +
find . -name ".yarn" -type d -exec rm -rf '{}' +
find . -name "packake-lock.json" -type f -exec rm -rf '{}' +
find . -name "yarn.lock" -type f -exec rm -rf '{}' +
find . -name "package-lock.json" -type f -exec rm -rf '{}' +
rm -rf ./pre-install/*.tgz
rm -rf ./extensions/*/*.tgz
@ -146,8 +145,8 @@ else
find . -name "build" -type d -exec rm -rf '{}' +
find . -name "out" -type d -exec rm -rf '{}' +
find . -name ".turbo" -type d -exec rm -rf '{}' +
find . -name ".yarn" -type d -exec rm -rf '{}' +
find . -name "package-lock.json" -type f -exec rm -rf '{}' +
find . -name "yarn.lock" -type f -exec rm -rf '{}' +
rm -rf ./pre-install/*.tgz
rm -rf ./extensions/*/*.tgz
rm -rf ./electron/pre-install/*.tgz

View File

@ -1,15 +1,16 @@
{
"name": "@janhq/core",
"version": "0.1.10",
"description": "Jan app core lib",
"description": "Core library for the Jan AI application framework",
"keywords": [
"jan",
"core"
],
"homepage": "https://jan.ai",
"license": "AGPL-3.0",
"main": "dist/core.es5.js",
"module": "dist/core.cjs.js",
"browser": "dist/index.js",
"main": "dist/index.js",
"module": "dist/node/index.cjs.js",
"typings": "dist/types/index.d.ts",
"files": [
"dist",
@ -17,13 +18,13 @@
],
"author": "Jan <service@jan.ai>",
"exports": {
".": "./dist/core.es5.js",
".": "./dist/index.js",
"./node": "./dist/node/index.cjs.js"
},
"typesVersions": {
"*": {
".": [
"./dist/core.es5.js.map",
"./dist/index.js.map",
"./dist/types/index.d.ts"
],
"node": [
@ -36,25 +37,25 @@
"lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'",
"test": "jest",
"prebuild": "rimraf dist",
"build": "tsc --module commonjs && rollup -c rollup.config.ts",
"start": "rollup -c rollup.config.ts -w"
"build": "tsc -p . && rolldown -c rolldown.config.mjs"
},
"devDependencies": {
"@rollup/plugin-replace": "^5.0.5",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.4",
"@npmcli/arborist": "^7.1.0",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.0",
"@types/pacote": "^11.1.7",
"@types/request": "^2.48.12",
"electron": "33.2.1",
"eslint": "8.57.0",
"eslint-plugin-jest": "^27.9.0",
"jest": "^29.7.0",
"jest-junit": "^16.0.0",
"jest-runner": "^29.7.0",
"pacote": "^21.0.0",
"request": "^2.88.2",
"request-progress": "^3.0.0",
"rimraf": "^3.0.2",
"rollup": "^2.38.5",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"rolldown": "1.0.0-beta.1",
"ts-jest": "^29.2.5",
"tslib": "^2.6.2",
"typescript": "^5.3.3"
@ -62,5 +63,6 @@
"dependencies": {
"rxjs": "^7.8.1",
"ulidx": "^2.3.0"
}
},
"packageManager": "yarn@4.5.3"
}

51
core/rolldown.config.mjs Normal file
View File

@ -0,0 +1,51 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
export default defineConfig([
{
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
sourcemap: true,
},
platform: 'browser',
external: ['path'],
define: {
NODE: JSON.stringify(`${pkgJson.name}/${pkgJson.node}`),
VERSION: JSON.stringify(pkgJson.version),
},
},
{
input: 'src/node/index.ts',
external: [
'fs/promises',
'path',
'pacote',
'@types/pacote',
'@npmcli/arborist',
'ulidx',
'node-fetch',
'fs',
'request',
'crypto',
'url',
'http',
'os',
'util',
'child_process',
'electron',
'request-progress',
],
output: {
format: 'cjs',
file: 'dist/node/index.cjs.js',
sourcemap: true,
inlineDynamicImports: true,
},
resolve: {
extensions: ['.js', '.ts'],
},
platform: 'node',
},
])

View File

@ -1,85 +0,0 @@
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import sourceMaps from 'rollup-plugin-sourcemaps'
import typescript from 'rollup-plugin-typescript2'
import json from 'rollup-plugin-json'
import replace from '@rollup/plugin-replace'
const pkg = require('./package.json')
export default [
{
input: `src/index.ts`,
output: [
// { file: pkg.main, name: libraryName, format: 'umd', sourcemap: true },
{ file: pkg.main, format: 'es', sourcemap: true },
],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: ['path'],
watch: {
include: 'src/**',
},
plugins: [
// Allow json resolution
json(),
// Compile TypeScript files
typescript({ useTsconfigDeclarationDir: true }),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
replace({
'preventAssignment': true,
'node:crypto': 'crypto',
'delimiters': ['"', '"'],
}),
resolve({
browser: true,
}),
// Resolve source maps to the original source
sourceMaps(),
],
},
{
input: `src/node/index.ts`,
output: [{ file: 'dist/node/index.cjs.js', format: 'cjs', sourcemap: true }],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: [
'fs/promises',
'path',
'pacote',
'@types/pacote',
'@npmcli/arborist',
'ulidx',
'node-fetch',
'fs',
'request',
'crypto',
'url',
'http',
'os',
'util',
'child_process',
],
watch: {
include: 'src/node/**',
},
plugins: [
// Allow json resolution
json(),
// Compile TypeScript files
typescript({ useTsconfigDeclarationDir: true }),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
resolve(),
// Resolve source maps to the original source
sourceMaps(),
],
},
]

View File

@ -1,4 +1,9 @@
import { DownloadRequest, FileStat, NetworkConfig, SystemInformation } from '../types'
import {
DownloadRequest,
FileStat,
NetworkConfig,
SystemInformation,
} from '../types'
/**
* Execute a extension module function in main process
@ -9,11 +14,12 @@ import { DownloadRequest, FileStat, NetworkConfig, SystemInformation } from '../
* @returns Promise<any>
*
*/
const executeOnMain: (extension: string, method: string, ...args: any[]) => Promise<any> = (
extension,
method,
...args
) => globalThis.core?.api?.invokeExtensionFunc(extension, method, ...args)
const executeOnMain: (
extension: string,
method: string,
...args: any[]
) => Promise<any> = (extension, method, ...args) =>
globalThis.core?.api?.invokeExtensionFunc(extension, method, ...args)
/**
* Downloads a file from a URL and saves it to the local file system.
@ -23,10 +29,11 @@ const executeOnMain: (extension: string, method: string, ...args: any[]) => Prom
*
* @returns {Promise<any>} A promise that resolves when the file is downloaded.
*/
const downloadFile: (downloadRequest: DownloadRequest, network?: NetworkConfig) => Promise<any> = (
downloadRequest,
network
) => globalThis.core?.api?.downloadFile(downloadRequest, network)
const downloadFile: (
downloadRequest: DownloadRequest,
network?: NetworkConfig
) => Promise<any> = (downloadRequest, network) =>
globalThis.core?.api?.downloadFile(downloadRequest, network)
/**
* Aborts the download of a specific file.
@ -41,7 +48,8 @@ const abortDownload: (fileName: string) => Promise<any> = (fileName) =>
*
* @returns {Promise<string>} A Promise that resolves with Jan's data folder path.
*/
const getJanDataFolderPath = (): Promise<string> => globalThis.core.api?.getJanDataFolderPath()
const getJanDataFolderPath = (): Promise<string> =>
globalThis.core.api?.getJanDataFolderPath()
/**
* Opens the file explorer at a specific path.
@ -64,14 +72,16 @@ const joinPath: (paths: string[]) => Promise<string> = (paths) =>
* @param path - The file path to retrieve dirname.
* @returns {Promise<string>} A promise that resolves the dirname.
*/
const dirName: (path: string) => Promise<string> = (path) => globalThis.core.api?.dirName(path)
const dirName: (path: string) => Promise<string> = (path) =>
globalThis.core.api?.dirName(path)
/**
* Retrieve the basename from an url.
* @param path - The path to retrieve.
* @returns {Promise<string>} A promise that resolves with the basename.
*/
const baseName: (paths: string) => Promise<string> = (path) => globalThis.core.api?.baseName(path)
const baseName: (paths: string) => Promise<string> = (path) =>
globalThis.core.api?.baseName(path)
/**
* Opens an external URL in the default web browser.
@ -87,13 +97,15 @@ const openExternalUrl: (url: string) => Promise<any> = (url) =>
*
* @returns {Promise<string>} - A promise that resolves with the resource path.
*/
const getResourcePath: () => Promise<string> = () => globalThis.core.api?.getResourcePath()
const getResourcePath: () => Promise<string> = () =>
globalThis.core.api?.getResourcePath()
/**
* Gets the user's home path.
* @returns return user's home path
*/
const getUserHomePath = (): Promise<string> => globalThis.core.api?.getUserHomePath()
const getUserHomePath = (): Promise<string> =>
globalThis.core.api?.getUserHomePath()
/**
* Log to file from browser processes.
@ -111,8 +123,10 @@ const log: (message: string, fileName?: string) => void = (message, fileName) =>
*
* @returns {Promise<boolean>} - A promise that resolves with a boolean indicating whether the path is a subdirectory.
*/
const isSubdirectory: (from: string, to: string) => Promise<boolean> = (from: string, to: string) =>
globalThis.core.api?.isSubdirectory(from, to)
const isSubdirectory: (from: string, to: string) => Promise<boolean> = (
from: string,
to: string
) => globalThis.core.api?.isSubdirectory(from, to)
/**
* Get system information
@ -159,5 +173,4 @@ export {
systemInformation,
showToast,
dirName,
FileStat,
}

View File

@ -11,6 +11,7 @@ export enum ExtensionTypeEnum {
Model = 'model',
SystemMonitoring = 'systemMonitoring',
HuggingFace = 'huggingFace',
Engine = 'engine',
}
export interface ExtensionType {

View File

@ -0,0 +1,91 @@
import {
InferenceEngine,
Engines,
EngineVariant,
EngineReleased,
DefaultEngineVariant,
} from '../../types'
import { BaseExtension, ExtensionTypeEnum } from '../extension'
/**
* Engine management extension. Persists and retrieves engine management.
* @abstract
* @extends BaseExtension
*/
export abstract class EngineManagementExtension extends BaseExtension {
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.Engine
}
/**
* @returns A Promise that resolves to an object of list engines.
*/
abstract getEngines(): Promise<Engines>
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to an array of installed engine.
*/
abstract getInstalledEngines(name: InferenceEngine): Promise<EngineVariant[]>
/**
* @param name - Inference engine name.
* @param version - Version of the engine.
* @param platform - Optional to sort by operating system. macOS, linux, windows.
* @returns A Promise that resolves to an array of latest released engine by version.
*/
abstract getReleasedEnginesByVersion(
name: InferenceEngine,
version: string,
platform?: string
): Promise<EngineReleased[]>
/**
* @param name - Inference engine name.
* @param platform - Optional to sort by operating system. macOS, linux, windows.
* @returns A Promise that resolves to an array of latest released engine.
*/
abstract getLatestReleasedEngine(
name: InferenceEngine,
platform?: string
): Promise<EngineReleased[]>
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to intall of engine.
*/
abstract installEngine(
name: InferenceEngine,
engineConfig: { variant: string; version?: string }
): Promise<{ messages: string }>
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to unintall of engine.
*/
abstract uninstallEngine(
name: InferenceEngine,
engineConfig: { variant: string; version: string }
): Promise<{ messages: string }>
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to an object of default engine.
*/
abstract getDefaultEngineVariant(name: InferenceEngine): Promise<DefaultEngineVariant>
/**
* @body variant - string
* @body version - string
* @returns A Promise that resolves to set default engine.
*/
abstract setDefaultEngineVariant(
name: InferenceEngine,
engineConfig: { variant: string; version: string }
): Promise<{ messages: string }>
/**
* @returns A Promise that resolves to update engine.
*/
abstract updateEngine(name: InferenceEngine): Promise<{ messages: string }>
}

View File

@ -28,3 +28,8 @@ export { ModelExtension } from './model'
* Base AI Engines.
*/
export * from './engines'
/**
* Engines Management
*/
export * from './enginesManagement'

View File

@ -4,16 +4,6 @@ jest.mock('../../helper', () => ({
}))
import { App } from './app'
it('should call stopServer', () => {
const app = new App()
const stopServerMock = jest.fn().mockResolvedValue('Server stopped')
jest.mock('@janhq/server', () => ({
stopServer: stopServerMock,
}))
app.stopServer()
expect(stopServerMock).toHaveBeenCalled()
})
it('should correctly retrieve basename', () => {
const app = new App()
const result = app.baseName('/path/to/file.txt')
@ -23,7 +13,8 @@ it('should correctly retrieve basename', () => {
it('should correctly identify subdirectories', () => {
const app = new App()
const basePath = process.platform === 'win32' ? 'C:\\path\\to' : '/path/to'
const subPath = process.platform === 'win32' ? 'C:\\path\\to\\subdir' : '/path/to/subdir'
const subPath =
process.platform === 'win32' ? 'C:\\path\\to\\subdir' : '/path/to/subdir'
const result = app.isSubdirectory(basePath, subPath)
expect(result).toBe(true)
})
@ -31,7 +22,8 @@ it('should correctly identify subdirectories', () => {
it('should correctly join multiple paths', () => {
const app = new App()
const result = app.joinPath(['path', 'to', 'file'])
const expectedPath = process.platform === 'win32' ? 'path\\to\\file' : 'path/to/file'
const expectedPath =
process.platform === 'win32' ? 'path\\to\\file' : 'path/to/file'
expect(result).toBe(expectedPath)
})
@ -52,5 +44,7 @@ it('should retrieve the directory name from a file path (Unix/Windows)', async (
it('should retrieve the directory name when using file protocol', async () => {
const app = new App()
const path = 'file:/models/file.txt'
expect(await app.dirName(path)).toBe(process.platform === 'win32' ? 'app\\models' : 'app/models')
expect(await app.dirName(path)).toBe(
process.platform === 'win32' ? 'app\\models' : 'app/models'
)
})

View File

@ -44,11 +44,8 @@ export class App implements Processor {
/**
* Checks if the given path is a subdirectory of the given directory.
*
* @param _event - The IPC event object.
* @param from - The path to check.
* @param to - The directory to check against.
*
* @returns {Promise<boolean>} - A promise that resolves with the result.
*/
isSubdirectory(from: any, to: any) {
const rel = relative(from, to)
@ -79,26 +76,4 @@ export class App implements Processor {
async updateAppConfiguration(args: any) {
await updateAppConfiguration(args)
}
/**
* Start Jan API Server.
*/
async startServer(args?: any) {
const { startServer } = require('@janhq/server')
return startServer({
host: args?.host,
port: args?.port,
isCorsEnabled: args?.isCorsEnabled,
isVerboseEnabled: args?.isVerboseEnabled,
prefix: args?.prefix,
})
}
/**
* Stop Jan API Server.
*/
stopServer() {
const { stopServer } = require('@janhq/server')
return stopServer()
}
}

View File

@ -57,7 +57,10 @@ export default class Extension {
* @type {string}
*/
get specifier() {
return this.origin + (this.installOptions.version ? '@' + this.installOptions.version : '')
return (
this.origin +
(this.installOptions.version ? '@' + this.installOptions.version : '')
)
}
/**
@ -75,8 +78,10 @@ export default class Extension {
async getManifest() {
// Get the package's manifest (package.json object)
try {
await import('pacote').then((pacote) => {
return pacote.manifest(this.specifier, this.installOptions).then((mnf) => {
const pacote = require('pacote')
return pacote
.manifest(this.specifier, this.installOptions)
.then((mnf: any) => {
// set the Package properties based on the it's manifest
this.name = mnf.name
this.productName = mnf.productName as string | undefined
@ -84,9 +89,10 @@ export default class Extension {
this.main = mnf.main
this.description = mnf.description
})
})
} catch (error) {
throw new Error(`Package ${this.origin} does not contain a valid manifest: ${error}`)
throw new Error(
`Package ${this.origin} does not contain a valid manifest: ${error}`
)
}
return true
@ -103,10 +109,13 @@ export default class Extension {
await this.getManifest()
// Install the package in a child folder of the given folder
const pacote = await import('pacote')
const pacote = require('pacote')
await pacote.extract(
this.specifier,
join(ExtensionManager.instance.getExtensionsPath() ?? '', this.name ?? ''),
join(
ExtensionManager.instance.getExtensionsPath() ?? '',
this.name ?? ''
),
this.installOptions
)
@ -169,13 +178,12 @@ export default class Extension {
* @returns the latest available version if a new version is available or false if not.
*/
async isUpdateAvailable() {
return import('pacote').then((pacote) => {
const pacote = require('pacote')
if (this.origin) {
return pacote.manifest(this.origin).then((mnf) => {
return pacote.manifest(this.origin).then((mnf: any) => {
return mnf.version !== this.version ? mnf.version : false
})
}
})
}
/**

View File

@ -27,7 +27,10 @@ export enum NativeRoute {
quickAskSizeUpdated = 'quickAskSizeUpdated',
ackDeepLink = 'ackDeepLink',
factoryReset = 'factoryReset'
factoryReset = 'factoryReset',
startServer = 'startServer',
stopServer = 'stopServer',
}
/**
@ -41,8 +44,6 @@ export enum AppRoute {
dirName = 'dirName',
isSubdirectory = 'isSubdirectory',
baseName = 'baseName',
startServer = 'startServer',
stopServer = 'stopServer',
log = 'log',
systemInformation = 'systemInformation',
showToast = 'showToast',

View File

@ -0,0 +1,28 @@
import { InferenceEngine } from '../../types'
export type Engines = {
[key in InferenceEngine]: EngineVariant[]
}
export type EngineVariant = {
engine: InferenceEngine
name: string
version: string
}
export type DefaultEngineVariant = {
engine: InferenceEngine
variant: string
version: string
}
export type EngineReleased = {
created_at: string
download_count: number
name: string
size: number
}
export enum EngineEvent {
OnEngineUpdate = 'OnEngineUpdate',
}

View File

@ -10,3 +10,4 @@ export * from './huggingface'
export * from './miscellaneous'
export * from './api'
export * from './setting'
export * from './engine'

View File

@ -11,11 +11,10 @@
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"declarationDir": "dist/types",
"outDir": "dist/lib",
"outDir": "dist",
"importHelpers": true,
"types": ["@types/jest"],
"resolveJsonModule": true
"types": ["jest", "node"]
},
"include": ["src"],
"exclude": ["**/*.test.ts"]
"exclude": ["src/**/*.test.ts"]
}

View File

@ -58,5 +58,5 @@
"prettier": "^3.2.5",
"typescript": "^5"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
"packageManager": "yarn@1.22.22"
}

0
docs/yarn.lock Normal file
View File

View File

@ -277,4 +277,39 @@ export function handleAppIPCs() {
ModuleManager.instance.clearImportedModules()
return createUserSpace().then(migrate).then(setupExtensions)
})
/**
* Handles the "startServer" IPC message to start the Jan API server.
* Initializes and starts server with provided configuration options.
* @param _event - The IPC event object.
* @param args - Configuration object containing host, port, CORS settings etc.
* @returns Promise that resolves when server starts successfully
*/
ipcMain.handle(
NativeRoute.startServer,
async (_event, args): Promise<void> => {
const { startServer } = require('@janhq/server')
return startServer({
host: args?.host,
port: args?.port,
isCorsEnabled: args?.isCorsEnabled,
isVerboseEnabled: args?.isVerboseEnabled,
prefix: args?.prefix,
})
}
)
/**
* Handles the "stopServer" IPC message to stop the Jan API server.
* Gracefully shuts down the server instance.
* @param _event - The IPC event object
* @returns Promise that resolves when server stops successfully
*/
ipcMain.handle(NativeRoute.stopServer, async (_event): Promise<void> => {
/**
* Stop Jan API Server.
*/
const { stopServer } = require('@janhq/server')
return stopServer()
})
}

View File

@ -78,9 +78,11 @@
},
"scripts": {
"lint": "eslint . --ext \".js,.jsx,.ts,.tsx\"",
"test:e2e": "playwright test --workers=1",
"test:e2e": "DEBUG=pw:browser xvfb-maybe -- playwright test --workers=1",
"copy:assets": "rimraf --glob \"./pre-install/*.tgz\" && cpx \"../pre-install/*.tgz\" \"./pre-install\"",
"dev": "yarn copy:assets && tsc -p . && electron .",
"version-patch": "jq '.version' package.json | tr -d '\"' > .version.bak && jq --arg ver \"0.1.$(date +%s)\" '.version = $ver' package.json > package.tmp && mv package.tmp package.json",
"version-restore": "jq --arg ver $(cat .version.bak) '.version = $ver' package.json > package.tmp && mv package.tmp package.json && rm .version.bak",
"dev": "yarn copy:assets && tsc -p . && yarn version-patch && electron . && yarn version-restore",
"compile": "tsc -p .",
"start": "electron .",
"build": "yarn copy:assets && run-script-os",
@ -98,22 +100,23 @@
},
"dependencies": {
"@alumna/reflect": "^1.1.3",
"@janhq/core": "link:./core",
"@janhq/server": "link:./server",
"@janhq/core": "link:../core",
"@janhq/server": "link:../server",
"@kirillvakalov/nut-tree__nut-js": "4.2.1-2",
"@npmcli/arborist": "^7.1.0",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"fs-extra": "^11.2.0",
"node-fetch": "2",
"pacote": "^17.0.4",
"pacote": "^21.0.0",
"request": "^2.88.2",
"request-progress": "^3.0.0",
"ulidx": "^2.3.0",
"@kirillvakalov/nut-tree__nut-js": "4.2.1-2"
"ulidx": "^2.3.0"
},
"devDependencies": {
"@electron/notarize": "^2.5.0",
"@playwright/test": "^1.38.1",
"@reportportal/agent-js-playwright": "^5.1.7",
"@types/npmcli__arborist": "^5.6.4",
"@types/pacote": "^11.1.7",
"@types/request": "^2.48.12",
@ -129,9 +132,10 @@
"rimraf": "^5.0.5",
"run-script-os": "^1.1.6",
"typescript": "^5.3.3",
"@reportportal/agent-js-playwright": "^5.1.7"
"xvfb-maybe": "^0.2.1"
},
"installConfig": {
"hoistingLimits": "workspaces"
}
},
"packageManager": "yarn@4.5.3"
}

View File

@ -36,7 +36,7 @@ export async function setupElectron() {
expect(appInfo).toBeTruthy()
electronApp = await electron.launch({
args: [appInfo.main], // main file from package.json
args: [appInfo.main, '--no-sandbox'], // main file from package.json
executablePath: appInfo.executable, // path to the Electron executable
// recordVideo: { dir: Constants.VIDEO_DIR }, // Specify the directory for video recordings
})

3
extensions/.yarnrc.yml Normal file
View File

@ -0,0 +1,3 @@
nmHoistingLimits: workspaces
nodeLinker: node-modules
checksumBehavior: update

View File

@ -1,7 +1,7 @@
{
"name": "@janhq/assistant-extension",
"productName": "Jan Assistant",
"version": "1.0.1",
"version": "1.0.2",
"description": "This extension enables assistants, including Jan, a default assistant that can call all downloaded models",
"main": "dist/index.js",
"node": "dist/node/index.js",
@ -9,33 +9,28 @@
"license": "AGPL-3.0",
"scripts": {
"clean:modules": "rimraf node_modules/pdf-parse/test && cd node_modules/pdf-parse/lib/pdf.js && rimraf v1.9.426 v1.10.88 v2.0.550",
"build-universal-hnswlib": "cd node_modules/hnswlib-node && arch -x86_64 npx node-gyp rebuild --arch=x64 && mv build/Release/addon.node ./addon-amd64.node && node-gyp rebuild --arch=arm64 && mv build/Release/addon.node ./addon-arm64.node && lipo -create -output build/Release/addon.node ./addon-arm64.node ./addon-amd64.node && rm ./addon-arm64.node && rm ./addon-amd64.node",
"build": "yarn clean:modules && tsc --module commonjs && rollup -c rollup.config.ts",
"build:publish:linux": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install",
"build:publish:darwin": "rimraf *.tgz --glob && yarn build-universal-hnswlib && yarn build && ../../.github/scripts/auto-sign.sh && npm pack && cpx *.tgz ../../pre-install",
"build:publish:win32": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install",
"build:publish": "run-script-os"
"build-universal-hnswlib": "[ \"$IS_TEST\" = \"true\" ] && echo \"Skip universal build\" || (cd node_modules/hnswlib-node && arch -x86_64 npx node-gyp rebuild --arch=x64 && mv build/Release/addon.node ./addon-amd64.node && node-gyp rebuild --arch=arm64 && mv build/Release/addon.node ./addon-arm64.node && lipo -create -output build/Release/addon.node ./addon-arm64.node ./addon-amd64.node && rm ./addon-arm64.node && rm ./addon-amd64.node)",
"build": "yarn clean:modules && rolldown -c rolldown.config.mjs",
"build:publish:linux": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install",
"build:publish:darwin": "rimraf *.tgz --glob || true && yarn build-universal-hnswlib && yarn build && ../../.github/scripts/auto-sign.sh && npm pack && cpx *.tgz ../../pre-install",
"build:publish:win32": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install",
"build:publish": "run-script-os",
"build:dev": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5",
"@types/pdf-parse": "^1.1.4",
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"rollup": "^2.38.5",
"rollup-plugin-define": "^1.0.1",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"typescript": "^5.3.3",
"run-script-os": "^1.1.6"
"rolldown": "1.0.0-beta.1",
"run-script-os": "^1.1.6",
"typescript": "^5.3.3"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"@langchain/community": "0.0.13",
"hnswlib-node": "^1.4.2",
"langchain": "^0.0.214",
"node-gyp": "^11.0.0",
"pdf-parse": "^1.1.1",
"ts-loader": "^9.5.0"
},
@ -47,5 +42,9 @@
"bundleDependencies": [
"@janhq/core",
"hnswlib-node"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,31 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
export default defineConfig([
{
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
NODE: JSON.stringify(`${pkgJson.name}/${pkgJson.node}`),
VERSION: JSON.stringify(pkgJson.version),
},
},
{
input: 'src/node/index.ts',
external: ['@janhq/core/node', 'path', 'hnswlib-node'],
output: {
format: 'cjs',
file: 'dist/node/index.js',
sourcemap: false,
inlineDynamicImports: true,
},
resolve: {
extensions: ['.js', '.ts'],
},
platform: 'node',
},
])

View File

@ -1,73 +0,0 @@
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import sourceMaps from 'rollup-plugin-sourcemaps'
import typescript from 'rollup-plugin-typescript2'
import json from '@rollup/plugin-json'
import replace from '@rollup/plugin-replace'
const packageJson = require('./package.json')
export default [
{
input: `src/index.ts`,
output: [{ file: packageJson.main, format: 'es', sourcemap: true }],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: [],
watch: {
include: 'src/**',
},
plugins: [
replace({
preventAssignment: true,
NODE: JSON.stringify(`${packageJson.name}/${packageJson.node}`),
VERSION: JSON.stringify(packageJson.version),
}),
// Allow json resolution
json(),
// Compile TypeScript files
typescript({ useTsconfigDeclarationDir: true }),
// Compile TypeScript files
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
resolve({
extensions: ['.js', '.ts', '.svelte'],
browser: true,
}),
// Resolve source maps to the original source
sourceMaps(),
],
},
{
input: `src/node/index.ts`,
output: [{ dir: 'dist/node', format: 'cjs', sourcemap: false }],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: ['@janhq/core/node', 'path', 'hnswlib-node'],
watch: {
include: 'src/node/**',
},
// inlineDynamicImports: true,
plugins: [
// Allow json resolution
json(),
// Compile TypeScript files
typescript({ useTsconfigDeclarationDir: true }),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs({
ignoreDynamicRequires: true,
}),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
resolve({
extensions: ['.ts', '.js', '.json'],
}),
// Resolve source maps to the original source
// sourceMaps(),
],
},
]

View File

@ -1,4 +1,4 @@
import { getJanDataFolderPath, normalizeFilePath } from '@janhq/core/node'
import { getJanDataFolderPath } from '@janhq/core/node'
import { retrieval } from './retrieval'
import path from 'path'

View File

@ -1,10 +1,10 @@
{
"compilerOptions": {
"moduleResolution": "node",
"target": "ES2015",
"module": "ES2020",
"lib": ["es2015", "es2016", "es2017", "dom"],
"strict": true,
"target": "es2016",
"module": "ES6",
"esModuleInterop": true,
"strict": false,
"sourceMap": true,
"declaration": true,
"allowSyntheticDefaultImports": true,

View File

@ -8,8 +8,8 @@
"license": "MIT",
"scripts": {
"test": "jest",
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
@ -18,12 +18,12 @@
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4"
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"ky": "^1.7.2",
"p-queue": "^8.0.1"
},
@ -35,5 +35,9 @@
"package.json",
"README.md"
],
"bundleDependencies": []
"bundleDependencies": [],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,14 @@
import { defineConfig } from 'rolldown'
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
API_URL: JSON.stringify('http://127.0.0.1:39291'),
SOCKET_URL: JSON.stringify('ws://127.0.0.1:39291'),
},
})

View File

@ -1,5 +1,3 @@
export {}
declare global {
declare const API_URL: string
declare const SOCKET_URL: string
@ -11,4 +9,3 @@ declare global {
core?: Core | undefined
electronAPI?: any | undefined
}
}

View File

@ -1,34 +0,0 @@
const webpack = require('webpack')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
plugins: [
new webpack.DefinePlugin({
API_URL: JSON.stringify('http://127.0.0.1:39291'),
SOCKET_URL: JSON.stringify('ws://127.0.0.1:39291'),
}),
],
resolve: {
extensions: ['.ts', '.js'],
},
// Do not minify the output, otherwise it breaks the class registration
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

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

View File

@ -0,0 +1,44 @@
{
"name": "@janhq/engine-management-extension",
"productName": "Engine Management",
"version": "1.0.0",
"description": "Extension for managing engines and their configurations",
"main": "dist/index.js",
"node": "dist/node/index.cjs.js",
"author": "Jan <service@jan.ai>",
"license": "MIT",
"scripts": {
"test": "jest",
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && ../../.github/scripts/auto-sign.sh && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"rolldown": "^1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.3.3"
},
"dependencies": {
"@janhq/core": "../../core/package.tgz",
"cpu-instructions": "^0.0.13",
"ky": "^1.7.2",
"p-queue": "^8.0.1"
},
"bundledDependencies": [
"cpu-instructions",
"@janhq/core"
],
"engines": {
"node": ">=18.0.0"
},
"files": [
"dist/*",
"package.json",
"README.md"
]
}

View File

@ -0,0 +1,40 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
export default defineConfig([
{
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
define: {
NODE: JSON.stringify(`${pkgJson.name}/${pkgJson.node}`),
API_URL: JSON.stringify('http://127.0.0.1:39291'),
SOCKET_URL: JSON.stringify('ws://127.0.0.1:39291'),
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.42'),
},
},
{
input: 'src/node/index.ts',
external: ['@janhq/core/node'],
output: {
format: 'cjs',
file: 'dist/node/index.cjs.js',
},
define: {
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.42'),
},
},
{
input: 'src/node/cpuInfo.ts',
output: {
format: 'cjs',
file: 'dist/node/cpuInfo.js',
},
external: ['cpu-instructions'],
resolve: {
extensions: ['.ts', '.js', '.svg'],
},
},
])

View File

@ -0,0 +1,13 @@
declare const API_URL: string
declare const CORTEX_ENGINE_VERSION: string
declare const SOCKET_URL: string
declare const NODE: string
interface Core {
api: APIFunctions
events: EventEmitter
}
interface Window {
core?: Core | undefined
electronAPI?: any | undefined
}

View File

@ -0,0 +1,10 @@
/**
* Custom Engine Error
*/
export class EngineError extends Error {
message: string
constructor(message: string) {
super()
this.message = message
}
}

View File

@ -0,0 +1,219 @@
import {
EngineManagementExtension,
InferenceEngine,
DefaultEngineVariant,
Engines,
EngineVariant,
EngineReleased,
executeOnMain,
systemInformation,
} from '@janhq/core'
import ky, { HTTPError } from 'ky'
import PQueue from 'p-queue'
import { EngineError } from './error'
/**
* JSONEngineManagementExtension is a EngineManagementExtension implementation that provides
* functionality for managing engines.
*/
export default class JSONEngineManagementExtension extends EngineManagementExtension {
queue = new PQueue({ concurrency: 1 })
/**
* Called when the extension is loaded.
*/
async onLoad() {
// Symlink Engines Directory
await executeOnMain(NODE, 'symlinkEngines')
// Run Healthcheck
this.queue.add(() => this.healthz())
try {
const variant = await this.getDefaultEngineVariant(
InferenceEngine.cortex_llamacpp
)
// Check whether should use bundled version or installed version
// Only use larger version
if (this.compareVersions(CORTEX_ENGINE_VERSION, variant.version) > 0) {
throw new EngineError(
'Default engine version is smaller than bundled version'
)
}
} catch (error) {
if (
(error instanceof HTTPError && error.response.status === 400) ||
error instanceof EngineError
) {
const systemInfo = await systemInformation()
const variant = await executeOnMain(
NODE,
'engineVariant',
systemInfo.gpuSetting
)
await this.setDefaultEngineVariant(InferenceEngine.cortex_llamacpp, {
variant: variant,
version: `${CORTEX_ENGINE_VERSION}`,
})
} else {
console.error('An unexpected error occurred:', error)
}
}
}
/**
* Called when the extension is unloaded.
*/
onUnload() {}
/**
* @returns A Promise that resolves to an object of list engines.
*/
async getEngines(): Promise<Engines> {
return this.queue.add(() =>
ky
.get(`${API_URL}/v1/engines`)
.json<Engines>()
.then((e) => e)
) as Promise<Engines>
}
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to an array of installed engine.
*/
async getInstalledEngines(name: InferenceEngine): Promise<EngineVariant[]> {
return this.queue.add(() =>
ky
.get(`${API_URL}/v1/engines/${name}`)
.json<EngineVariant[]>()
.then((e) => e)
) as Promise<EngineVariant[]>
}
/**
* @param name - Inference engine name.
* @param version - Version of the engine.
* @param platform - Optional to sort by operating system. macOS, linux, windows.
* @returns A Promise that resolves to an array of latest released engine by version.
*/
async getReleasedEnginesByVersion(
name: InferenceEngine,
version: string,
platform?: string
) {
return this.queue.add(() =>
ky
.get(`${API_URL}/v1/engines/${name}/releases/${version}`)
.json<EngineReleased[]>()
.then((e) =>
platform ? e.filter((r) => r.name.includes(platform)) : e
)
) as Promise<EngineReleased[]>
}
/**
* @param name - Inference engine name.
* @param platform - Optional to sort by operating system. macOS, linux, windows.
* @returns A Promise that resolves to an array of latest released engine by version.
*/
async getLatestReleasedEngine(name: InferenceEngine, platform?: string) {
return this.queue.add(() =>
ky
.get(`${API_URL}/v1/engines/${name}/releases/latest`)
.json<EngineReleased[]>()
.then((e) =>
platform ? e.filter((r) => r.name.includes(platform)) : e
)
) as Promise<EngineReleased[]>
}
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to intall of engine.
*/
async installEngine(
name: InferenceEngine,
engineConfig: { variant: string; version?: string }
) {
return this.queue.add(() =>
ky
.post(`${API_URL}/v1/engines/${name}/install`, { json: engineConfig })
.then((e) => e)
) as Promise<{ messages: string }>
}
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to unintall of engine.
*/
async uninstallEngine(
name: InferenceEngine,
engineConfig: { variant: string; version: string }
) {
return this.queue.add(() =>
ky
.delete(`${API_URL}/v1/engines/${name}/install`, { json: engineConfig })
.then((e) => e)
) as Promise<{ messages: string }>
}
/**
* @param name - Inference engine name.
* @returns A Promise that resolves to an object of default engine.
*/
async getDefaultEngineVariant(name: InferenceEngine) {
return this.queue.add(() =>
ky
.get(`${API_URL}/v1/engines/${name}/default`)
.json<{ messages: string }>()
.then((e) => e)
) as Promise<DefaultEngineVariant>
}
/**
* @body variant - string
* @body version - string
* @returns A Promise that resolves to set default engine.
*/
async setDefaultEngineVariant(
name: InferenceEngine,
engineConfig: { variant: string; version: string }
) {
return this.queue.add(() =>
ky
.post(`${API_URL}/v1/engines/${name}/default`, { json: engineConfig })
.then((e) => e)
) as Promise<{ messages: string }>
}
/**
* @returns A Promise that resolves to update engine.
*/
async updateEngine(name: InferenceEngine) {
return this.queue.add(() =>
ky.post(`${API_URL}/v1/engines/${name}/update`).then((e) => e)
) as Promise<{ messages: string }>
}
/**
* Do health check on cortex.cpp
* @returns
*/
async healthz(): Promise<void> {
return ky
.get(`${API_URL}/healthz`, {
retry: { limit: 20, delay: () => 500, methods: ['get'] },
})
.then(() => {})
}
private compareVersions(version1: string, version2: string): number {
const parseVersion = (version: string) => version.split('.').map(Number)
const [major1, minor1, patch1] = parseVersion(version1.replace(/^v/, ''))
const [major2, minor2, patch2] = parseVersion(version2.replace(/^v/, ''))
if (major1 !== major2) return major1 - major2
if (minor1 !== minor2) return minor1 - minor2
return patch1 - patch2
}
}

View File

@ -1,5 +1,5 @@
import { describe, expect, it } from '@jest/globals'
import { engineVariant, executableCortexFile } from './execute'
import engine from './index'
import { GpuSetting } from '@janhq/core/node'
import { cpuInfo } from 'cpu-instructions'
import { fork } from 'child_process'
@ -62,20 +62,9 @@ describe('test executable cortex file', () => {
Object.defineProperty(process, 'arch', {
value: 'arm64',
})
expect(executableCortexFile(testSettings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath:
originalPlatform === 'darwin'
? expect.stringContaining(`cortex-server`)
: expect.anything(),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
mockFork.mockReturnValue(mockProcess)
expect(engineVariant(testSettings)).resolves.toEqual('mac-arm64')
expect(engine.engineVariant(testSettings)).resolves.toEqual('mac-arm64')
})
it('executes on MacOS', () => {
@ -99,18 +88,7 @@ describe('test executable cortex file', () => {
value: 'x64',
})
expect(executableCortexFile(testSettings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath:
originalPlatform === 'darwin'
? expect.stringContaining(`cortex-server`)
: expect.anything(),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant(testSettings)).resolves.toEqual('mac-amd64')
expect(engine.engineVariant(testSettings)).resolves.toEqual('mac-amd64')
})
it('executes on Windows CPU', () => {
@ -131,15 +109,7 @@ describe('test executable cortex file', () => {
}
mockFork.mockReturnValue(mockProcess)
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant()).resolves.toEqual('windows-amd64-avx')
expect(engine.engineVariant()).resolves.toEqual('windows-amd64-avx')
})
it('executes on Windows Cuda 11', () => {
@ -176,15 +146,8 @@ describe('test executable cortex file', () => {
send: jest.fn(),
}
mockFork.mockReturnValue(mockProcess)
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
'windows-amd64-avx2-cuda-11-7'
)
})
@ -221,15 +184,8 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
'windows-amd64-noavx-cuda-12-0'
)
mockFork.mockReturnValue({
@ -240,7 +196,7 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
'windows-amd64-avx2-cuda-12-0'
)
})
@ -261,15 +217,8 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant()).resolves.toEqual('linux-amd64-noavx')
expect(engine.engineVariant()).resolves.toEqual('linux-amd64-noavx')
})
it('executes on Linux Cuda 11', () => {
@ -306,15 +255,9 @@ describe('test executable cortex file', () => {
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
expect(engine.engineVariant(settings)).resolves.toBe(
'linux-amd64-avx2-cuda-11-7'
)
expect(engineVariant(settings)).resolves.toBe('linux-amd64-avx2-cuda-11-7')
})
it('executes on Linux Cuda 12', () => {
@ -349,15 +292,8 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
'linux-amd64-avx2-cuda-12-0'
)
})
@ -383,16 +319,7 @@ describe('test executable cortex file', () => {
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
`linux-amd64-${instruction}`
)
})
@ -416,15 +343,7 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
`windows-amd64-${instruction}`
)
})
@ -465,15 +384,7 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
`windows-amd64-${instruction === 'avx512' || instruction === 'avx2' ? 'avx2' : 'noavx'}-cuda-12-0`
)
})
@ -514,15 +425,7 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
expect(engine.engineVariant(settings)).resolves.toEqual(
`linux-amd64-${instruction === 'avx512' || instruction === 'avx2' ? 'avx2' : 'noavx'}-cuda-12-0`
)
})
@ -564,50 +467,8 @@ describe('test executable cortex file', () => {
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(`linux-amd64-vulkan`)
})
})
// Generate test for different cpu instructions on MacOS
it(`executes on MacOS with different instructions`, () => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
})
const cpuInstructions = ['avx512', 'avx2', 'avx', 'noavx']
cpuInstructions.forEach(() => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
})
const settings: GpuSetting = {
...testSettings,
run_mode: 'cpu',
}
mockFork.mockReturnValue({
on: jest.fn((event, callback) => {
if (event === 'message') {
callback('noavx')
}
}),
send: jest.fn(),
})
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath:
originalPlatform === 'darwin'
? expect.stringContaining(`cortex-server`)
: expect.anything(),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
expect(engine.engineVariant(settings)).resolves.toEqual(
`linux-amd64-vulkan`
)
})
})

View File

@ -1,13 +1,13 @@
import * as path from 'path'
import { GpuSetting, appResourcePath, log } from '@janhq/core/node'
import {
appResourcePath,
getJanDataFolderPath,
GpuSetting,
log,
} from '@janhq/core/node'
import { fork } from 'child_process'
import { mkdir, readdir, symlink } from 'fs/promises'
export interface CortexExecutableOptions {
enginePath: string
executablePath: string
cudaVisibleDevices: string
vkVisibleDevices: string
}
/**
* The GPU runMode that will be set - either 'vulkan', 'cuda', or empty for cpu.
* @param settings
@ -37,14 +37,6 @@ const os = (): string => {
: 'linux-amd64'
}
/**
* The cortex.cpp extension based on the current platform.
* @returns .exe if on Windows, otherwise an empty string.
*/
const extension = (): '.exe' | '' => {
return process.platform === 'win32' ? '.exe' : ''
}
/**
* The CUDA version that will be set - either '11-7' or '12-0'.
* @param settings
@ -89,30 +81,10 @@ const cpuInstructions = async (): Promise<string> => {
})
}
/**
* The executable options for the cortex.cpp extension.
*/
export const executableCortexFile = (
gpuSetting?: GpuSetting
): CortexExecutableOptions => {
let cudaVisibleDevices = gpuSetting?.gpus_in_use.join(',') ?? ''
let vkVisibleDevices = gpuSetting?.gpus_in_use.join(',') ?? ''
let binaryName = `cortex-server${extension()}`
const binPath = path.join(__dirname, '..', 'bin')
return {
enginePath: path.join(appResourcePath(), 'shared'),
executablePath: path.join(binPath, binaryName),
cudaVisibleDevices,
vkVisibleDevices,
}
}
/**
* Find which variant to run based on the current platform.
*/
export const engineVariant = async (
gpuSetting?: GpuSetting
): Promise<string> => {
const engineVariant = async (gpuSetting?: GpuSetting): Promise<string> => {
const cpuInstruction = await cpuInstructions()
log(`[CORTEX]: CPU instruction: ${cpuInstruction}`)
let engineVariant = [
@ -135,3 +107,45 @@ export const engineVariant = async (
log(`[CORTEX]: Engine variant: ${engineVariant}`)
return engineVariant
}
/**
* Create symlink to each variant for the default bundled version
*/
const symlinkEngines = async () => {
const sourceEnginePath = path.join(
appResourcePath(),
'shared',
'engines',
'cortex.llamacpp'
)
const symlinkEnginePath = path.join(
getJanDataFolderPath(),
'engines',
'cortex.llamacpp'
)
const variantFolders = await readdir(sourceEnginePath)
for (const variant of variantFolders) {
const targetVariantPath = path.join(
sourceEnginePath,
variant,
CORTEX_ENGINE_VERSION
)
const symlinkVariantPath = path.join(
symlinkEnginePath,
variant,
CORTEX_ENGINE_VERSION
)
await mkdir(path.join(symlinkEnginePath, variant), {
recursive: true,
}).catch(console.error)
await symlink(targetVariantPath, symlinkVariantPath).catch(console.error)
console.log(`Symlink created: ${targetVariantPath} -> ${symlinkEnginePath}`)
}
}
export default {
engineVariant,
symlinkEngines,
}

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "es2016",
"module": "ES6",
"moduleResolution": "node",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": false,
"skipLibCheck": true,
"rootDir": "./src"
},
"include": ["./src"],
"exclude": ["src/**/*.test.ts", "rolldown.config.mjs"]
}

View File

@ -4,29 +4,23 @@
"version": "1.0.3",
"description": "This extension enables Anthropic chat completion API calls",
"main": "dist/index.js",
"module": "dist/module.js",
"engine": "anthropic",
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"test": "jest test",
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install",
"sync:core": "cd ../.. && yarn build:core && cd extensions && rm yarn.lock && cd inference-anthropic-extension && yarn && yarn build:publish"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"ulidx": "^2.3.0"
},
@ -40,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -10,9 +10,6 @@ import { RemoteOAIEngine } from '@janhq/core'
import { PayloadType } from '@janhq/core'
import { ChatCompletionRole } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
export enum Settings {
apiKey = 'anthropic-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint',

View File

@ -1,37 +0,0 @@
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -9,9 +9,8 @@
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install",
"sync:core": "cd ../.. && yarn build:core && cd extensions && rm yarn.lock && cd inference-cohere-extension && yarn && yarn build:publish"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
@ -20,12 +19,12 @@
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"ulidx": "^2.3.0"
},
@ -39,5 +38,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -10,9 +10,6 @@ import { RemoteOAIEngine } from '@janhq/core'
import { PayloadType } from '@janhq/core'
import { ChatCompletionRole } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings {
apiKey = 'cohere-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint',

View File

@ -1,37 +0,0 @@
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -1 +1 @@
1.0.6
1.0.7

View File

@ -30,8 +30,6 @@ if [ "$OS_TYPE" == "Linux" ]; then
download "${ENGINE_DOWNLOAD_URL}-linux-amd64-vulkan.tar.gz" -e --strip 1 -o "${SHARED_PATH}/engines/cortex.llamacpp/linux-amd64-vulkan/v${ENGINE_VERSION}" 1
download "${CUDA_DOWNLOAD_URL}/cuda-12-0-linux-amd64.tar.gz" -e --strip 1 -o "${SHARED_PATH}" 1
download "${CUDA_DOWNLOAD_URL}/cuda-11-7-linux-amd64.tar.gz" -e --strip 1 -o "${SHARED_PATH}" 1
mkdir -p "${SHARED_PATH}/engines/cortex.llamacpp/deps"
touch "${SHARED_PATH}/engines/cortex.llamacpp/deps/keep"
elif [ "$OS_TYPE" == "Darwin" ]; then
# macOS downloads

View File

@ -9,12 +9,12 @@
"license": "AGPL-3.0",
"scripts": {
"test": "jest",
"build": "tsc --module commonjs && rollup -c rollup.config.ts",
"build": "rolldown -c rolldown.config.mjs",
"downloadcortex:linux:darwin": "./download.sh",
"downloadcortex:win32": "download.bat",
"downloadcortex": "run-script-os",
"build:publish:darwin": "rimraf *.tgz --glob && yarn build && npm run downloadcortex && ../../.github/scripts/auto-sign.sh && cpx \"bin/**\" \"dist/bin\" && npm pack && cpx *.tgz ../../pre-install",
"build:publish:win32:linux": "rimraf *.tgz --glob && yarn build && npm run downloadcortex && cpx \"bin/**\" \"dist/bin\" && npm pack && cpx *.tgz ../../pre-install",
"build:publish:darwin": "rimraf *.tgz --glob || true && yarn build && yarn downloadcortex && ../../.github/scripts/auto-sign.sh && cpx \"bin/**\" \"dist/bin\" && npm pack && cpx *.tgz ../../pre-install",
"build:publish:win32:linux": "rimraf *.tgz --glob || true && yarn build && yarn downloadcortex && cpx \"bin/**\" \"dist/bin\" && npm pack && cpx *.tgz ../../pre-install",
"build:publish": "run-script-os"
},
"exports": {
@ -22,12 +22,7 @@
"./main": "./dist/node/index.cjs.js"
},
"devDependencies": {
"@babel/preset-typescript": "^7.24.1",
"@jest/globals": "^29.7.0",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5",
"@types/decompress": "^4.2.7",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.4",
@ -37,17 +32,13 @@
"download-cli": "^1.1.1",
"jest": "^29.7.0",
"rimraf": "^3.0.2",
"rollup": "^2.38.5",
"rollup-plugin-define": "^1.0.1",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"rolldown": "1.0.0-beta.1",
"run-script-os": "^1.1.6",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3"
},
"dependencies": {
"@janhq/core": "file:../../core",
"cpu-instructions": "^0.0.13",
"@janhq/core": "../../core/package.tgz",
"decompress": "^4.2.1",
"fetch-retry": "^5.0.6",
"ky": "^1.7.2",
@ -69,7 +60,10 @@
"tcp-port-used",
"fetch-retry",
"@janhq/core",
"decompress",
"cpu-instructions"
]
"decompress"
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,131 @@
import { defineConfig } from 'rolldown'
import packageJson from './package.json' with { type: 'json' }
import defaultSettingJson from './resources/default_settings.json' with { type: 'json' }
import bakllavaJson from './resources/models/bakllava-1/model.json' with { type: 'json' }
import codeninja7bJson from './resources/models/codeninja-1.0-7b/model.json' with { type: 'json' }
import commandr34bJson from './resources/models/command-r-34b/model.json' with { type: 'json' }
import deepseekCoder13bJson from './resources/models/deepseek-coder-1.3b/model.json' with { type: 'json' }
import deepseekCoder34bJson from './resources/models/deepseek-coder-34b/model.json' with { type: 'json' }
import gemma112bJson from './resources/models/gemma-1.1-2b/model.json' with { type: 'json' }
import gemma117bJson from './resources/models/gemma-1.1-7b/model.json' with { type: 'json' }
import llama2Chat70bJson from './resources/models/llama2-chat-70b/model.json' with { type: 'json' }
import llama2Chat7bJson from './resources/models/llama2-chat-7b/model.json' with { type: 'json' }
import llamacorn1bJson from './resources/models/llamacorn-1.1b/model.json' with { type: 'json' }
import llava13bJson from './resources/models/llava-13b/model.json' with { type: 'json' }
import llava7bJson from './resources/models/llava-7b/model.json' with { type: 'json' }
import mistralIns7bq4Json from './resources/models/mistral-ins-7b-q4/model.json' with { type: 'json' }
import mixtral8x7bInstructJson from './resources/models/mixtral-8x7b-instruct/model.json' with { type: 'json' }
import noromaid7bJson from './resources/models/noromaid-7b/model.json' with { type: 'json' }
import openchat357bJson from './resources/models/openchat-3.5-7b/model.json' with { type: 'json' }
import phi3bJson from './resources/models/phi3-3.8b/model.json' with { type: 'json' }
import phind34bJson from './resources/models/phind-34b/model.json' with { type: 'json' }
import qwen7bJson from './resources/models/qwen-7b/model.json' with { type: 'json' }
import stableZephyr3bJson from './resources/models/stable-zephyr-3b/model.json' with { type: 'json' }
import stealthv127bJson from './resources/models/stealth-v1.2-7b/model.json' with { type: 'json' }
import tinyllama11bJson from './resources/models/tinyllama-1.1b/model.json' with { type: 'json' }
import trinityv127bJson from './resources/models/trinity-v1.2-7b/model.json' with { type: 'json' }
import vistral7bJson from './resources/models/vistral-7b/model.json' with { type: 'json' }
import wizardcoder13bJson from './resources/models/wizardcoder-13b/model.json' with { type: 'json' }
import yi34bJson from './resources/models/yi-34b/model.json' with { type: 'json' }
import llama3Json from './resources/models/llama3-8b-instruct/model.json' with { type: 'json' }
import llama3Hermes8bJson from './resources/models/llama3-hermes-8b/model.json' with { type: 'json' }
import aya8bJson from './resources/models/aya-23-8b/model.json' with { type: 'json' }
import aya35bJson from './resources/models/aya-23-35b/model.json' with { type: 'json' }
import phimediumJson from './resources/models/phi3-medium/model.json' with { type: 'json' }
import codestralJson from './resources/models/codestral-22b/model.json' with { type: 'json' }
import qwen2Json from './resources/models/qwen2-7b/model.json' with { type: 'json' }
import llama318bJson from './resources/models/llama3.1-8b-instruct/model.json' with { type: 'json' }
import llama3170bJson from './resources/models/llama3.1-70b-instruct/model.json' with { type: 'json' }
import gemma22bJson from './resources/models/gemma-2-2b/model.json' with { type: 'json' }
import gemma29bJson from './resources/models/gemma-2-9b/model.json' with { type: 'json' }
import gemma227bJson from './resources/models/gemma-2-27b/model.json' with { type: 'json' }
import llama321bJson from './resources/models/llama3.2-1b-instruct/model.json' with { type: 'json' }
import llama323bJson from './resources/models/llama3.2-3b-instruct/model.json' with { type: 'json' }
import qwen257bJson from './resources/models/qwen2.5-7b-instruct/model.json' with { type: 'json' }
import qwen25coder7bJson from './resources/models/qwen2.5-coder-7b-instruct/model.json' with { type: 'json' }
import qwen25coder14bJson from './resources/models/qwen2.5-coder-14b-instruct/model.json' with { type: 'json' }
import qwen25coder32bJson from './resources/models/qwen2.5-coder-32b-instruct/model.json' with { type: 'json' }
import qwen2514bJson from './resources/models/qwen2.5-14b-instruct/model.json' with { type: 'json' }
import qwen2532bJson from './resources/models/qwen2.5-32b-instruct/model.json' with { type: 'json' }
import qwen2572bJson from './resources/models/qwen2.5-72b-instruct/model.json' with { type: 'json' }
export default defineConfig([
{
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify([
bakllavaJson,
codeninja7bJson,
commandr34bJson,
deepseekCoder13bJson,
deepseekCoder34bJson,
gemma112bJson,
gemma117bJson,
llama2Chat70bJson,
llama2Chat7bJson,
llamacorn1bJson,
llava13bJson,
llava7bJson,
mistralIns7bq4Json,
mixtral8x7bInstructJson,
noromaid7bJson,
openchat357bJson,
phi3bJson,
phind34bJson,
qwen7bJson,
stableZephyr3bJson,
stealthv127bJson,
tinyllama11bJson,
trinityv127bJson,
vistral7bJson,
wizardcoder13bJson,
yi34bJson,
llama3Json,
llama3Hermes8bJson,
phimediumJson,
aya8bJson,
aya35bJson,
codestralJson,
qwen2Json,
llama318bJson,
llama3170bJson,
gemma22bJson,
gemma29bJson,
gemma227bJson,
llama321bJson,
llama323bJson,
qwen257bJson,
qwen25coder7bJson,
qwen25coder14bJson,
qwen25coder32bJson,
qwen2514bJson,
qwen2532bJson,
qwen2572bJson,
]),
NODE: JSON.stringify(`${packageJson.name}/${packageJson.node}`),
SETTINGS: JSON.stringify(defaultSettingJson),
CORTEX_API_URL: JSON.stringify('http://127.0.0.1:39291'),
CORTEX_SOCKET_URL: JSON.stringify('ws://127.0.0.1:39291'),
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.42'),
},
},
{
input: 'src/node/index.ts',
external: ['@janhq/core/node', 'cpu-instructions'],
output: {
format: 'cjs',
file: 'dist/node/index.cjs.js',
sourcemap: false,
inlineDynamicImports: true,
},
resolve: {
extensions: ['.js', '.ts', '.json'],
},
platform: 'node',
},
])

View File

@ -1,177 +0,0 @@
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import sourceMaps from 'rollup-plugin-sourcemaps'
import typescript from 'rollup-plugin-typescript2'
import json from '@rollup/plugin-json'
import replace from '@rollup/plugin-replace'
const packageJson = require('./package.json')
const defaultSettingJson = require('./resources/default_settings.json')
const bakllavaJson = require('./resources/models/bakllava-1/model.json')
const codeninja7bJson = require('./resources/models/codeninja-1.0-7b/model.json')
const commandr34bJson = require('./resources/models/command-r-34b/model.json')
const deepseekCoder13bJson = require('./resources/models/deepseek-coder-1.3b/model.json')
const deepseekCoder34bJson = require('./resources/models/deepseek-coder-34b/model.json')
const gemma112bJson = require('./resources/models/gemma-1.1-2b/model.json')
const gemma117bJson = require('./resources/models/gemma-1.1-7b/model.json')
const llama2Chat70bJson = require('./resources/models/llama2-chat-70b/model.json')
const llama2Chat7bJson = require('./resources/models/llama2-chat-7b/model.json')
const llamacorn1bJson = require('./resources/models/llamacorn-1.1b/model.json')
const llava13bJson = require('./resources/models/llava-13b/model.json')
const llava7bJson = require('./resources/models/llava-7b/model.json')
const mistralIns7bq4Json = require('./resources/models/mistral-ins-7b-q4/model.json')
const mixtral8x7bInstructJson = require('./resources/models/mixtral-8x7b-instruct/model.json')
const noromaid7bJson = require('./resources/models/noromaid-7b/model.json')
const openchat357bJson = require('./resources/models/openchat-3.5-7b/model.json')
const phi3bJson = require('./resources/models/phi3-3.8b/model.json')
const phind34bJson = require('./resources/models/phind-34b/model.json')
const qwen7bJson = require('./resources/models/qwen-7b/model.json')
const stableZephyr3bJson = require('./resources/models/stable-zephyr-3b/model.json')
const stealthv127bJson = require('./resources/models/stealth-v1.2-7b/model.json')
const tinyllama11bJson = require('./resources/models/tinyllama-1.1b/model.json')
const trinityv127bJson = require('./resources/models/trinity-v1.2-7b/model.json')
const vistral7bJson = require('./resources/models/vistral-7b/model.json')
const wizardcoder13bJson = require('./resources/models/wizardcoder-13b/model.json')
const yi34bJson = require('./resources/models/yi-34b/model.json')
const llama3Json = require('./resources/models/llama3-8b-instruct/model.json')
const llama3Hermes8bJson = require('./resources/models/llama3-hermes-8b/model.json')
const aya8bJson = require('./resources/models/aya-23-8b/model.json')
const aya35bJson = require('./resources/models/aya-23-35b/model.json')
const phimediumJson = require('./resources/models/phi3-medium/model.json')
const codestralJson = require('./resources/models/codestral-22b/model.json')
const qwen2Json = require('./resources/models/qwen2-7b/model.json')
const llama318bJson = require('./resources/models/llama3.1-8b-instruct/model.json')
const llama3170bJson = require('./resources/models/llama3.1-70b-instruct/model.json')
const gemma22bJson = require('./resources/models/gemma-2-2b/model.json')
const gemma29bJson = require('./resources/models/gemma-2-9b/model.json')
const gemma227bJson = require('./resources/models/gemma-2-27b/model.json')
const llama321bJson = require('./resources/models/llama3.2-1b-instruct/model.json')
const llama323bJson = require('./resources/models/llama3.2-3b-instruct/model.json')
const qwen257bJson = require('./resources/models/qwen2.5-7b-instruct/model.json')
const qwen25coder7bJson = require('./resources/models/qwen2.5-coder-7b-instruct/model.json')
const qwen25coder14bJson = require('./resources/models/qwen2.5-coder-14b-instruct/model.json')
const qwen25coder32bJson = require('./resources/models/qwen2.5-coder-32b-instruct/model.json')
const qwen2514bJson = require('./resources/models/qwen2.5-14b-instruct/model.json')
const qwen2532bJson = require('./resources/models/qwen2.5-32b-instruct/model.json')
const qwen2572bJson = require('./resources/models/qwen2.5-72b-instruct/model.json')
export default [
{
input: `src/index.ts`,
output: [{ file: packageJson.main, format: 'es', sourcemap: true }],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: [],
watch: {
include: 'src/**',
},
plugins: [
replace({
preventAssignment: true,
MODELS: JSON.stringify([
bakllavaJson,
codeninja7bJson,
commandr34bJson,
deepseekCoder13bJson,
deepseekCoder34bJson,
gemma112bJson,
gemma117bJson,
llama2Chat70bJson,
llama2Chat7bJson,
llamacorn1bJson,
llava13bJson,
llava7bJson,
mistralIns7bq4Json,
mixtral8x7bInstructJson,
noromaid7bJson,
openchat357bJson,
phi3bJson,
phind34bJson,
qwen7bJson,
stableZephyr3bJson,
stealthv127bJson,
tinyllama11bJson,
trinityv127bJson,
vistral7bJson,
wizardcoder13bJson,
yi34bJson,
llama3Json,
llama3Hermes8bJson,
phimediumJson,
aya8bJson,
aya35bJson,
codestralJson,
qwen2Json,
llama318bJson,
llama3170bJson,
gemma22bJson,
gemma29bJson,
gemma227bJson,
llama321bJson,
llama323bJson,
qwen257bJson,
qwen25coder7bJson,
qwen25coder14bJson,
qwen25coder32bJson,
qwen2514bJson,
qwen2532bJson,
qwen2572bJson,
]),
NODE: JSON.stringify(`${packageJson.name}/${packageJson.node}`),
SETTINGS: JSON.stringify(defaultSettingJson),
CORTEX_API_URL: JSON.stringify('http://127.0.0.1:39291'),
CORTEX_SOCKET_URL: JSON.stringify('ws://127.0.0.1:39291'),
CORTEX_ENGINE_VERSION: JSON.stringify('v0.1.42'),
}),
// Allow json resolution
json(),
// Compile TypeScript files
typescript({
useTsconfigDeclarationDir: true,
exclude: ['**/__tests__', '**/*.test.ts'],
}),
// Compile TypeScript files
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
resolve({
extensions: ['.js', '.ts', '.svelte'],
browser: true,
}),
// Resolve source maps to the original source
sourceMaps(),
],
},
{
input: `src/node/index.ts`,
output: [
{ file: 'dist/node/index.cjs.js', format: 'cjs', sourcemap: true },
],
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: ['@janhq/core/node', 'cpu-instructions'],
watch: {
include: 'src/node/**',
},
plugins: [
// Allow json resolution
json(),
// Compile TypeScript files
typescript({
useTsconfigDeclarationDir: true,
exclude: ['**/__tests__', '**/*.test.ts'],
}),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
resolve({
extensions: ['.ts', '.js', '.json'],
}),
// Resolve source maps to the original source
sourceMaps(),
],
},
]

View File

@ -2,14 +2,5 @@ declare const NODE: string
declare const CORTEX_API_URL: string
declare const CORTEX_SOCKET_URL: string
declare const CORTEX_ENGINE_VERSION: string
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
/**
* The response from the initModel function.
* @property error - An error message if the model fails to load.
*/
interface ModelOperationResponse {
error?: any
modelFile?: string
}
declare const SETTINGS: object[]
declare const MODELS: object[]

View File

@ -1,6 +0,0 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
}

View File

@ -9,6 +9,7 @@
import {
Model,
executeOnMain,
EngineEvent,
systemInformation,
joinPath,
LocalOAIEngine,
@ -18,9 +19,7 @@ import {
fs,
events,
ModelEvent,
SystemInformation,
dirName,
AppConfigurationEventName,
} from '@janhq/core'
import PQueue from 'p-queue'
import ky from 'ky'
@ -112,21 +111,11 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
const systemInfo = await systemInformation()
this.queue.add(() => executeOnMain(NODE, 'run', systemInfo))
this.queue.add(() => this.healthz())
this.queue.add(() => this.setDefaultEngine(systemInfo))
this.subscribeToEvents()
window.addEventListener('beforeunload', () => {
this.clean()
})
const currentMode = systemInfo.gpuSetting?.run_mode
events.on(AppConfigurationEventName.OnConfigurationUpdate, async () => {
const systemInfo = await systemInformation()
// Update run mode on settings update
if (systemInfo.gpuSetting?.run_mode !== currentMode)
this.queue.add(() => this.setDefaultEngine(systemInfo))
})
}
async onUnload() {
@ -236,7 +225,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
* Do health check on cortex.cpp
* @returns
*/
private healthz(): Promise<void> {
private async healthz(): Promise<void> {
return ky
.get(`${CORTEX_API_URL}/healthz`, {
retry: {
@ -248,36 +237,11 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
.then(() => {})
}
/**
* Set default engine variant on launch
*/
private async setDefaultEngine(systemInfo: SystemInformation) {
const variant = await executeOnMain(
NODE,
'engineVariant',
systemInfo.gpuSetting
)
return (
ky
// Fallback support for legacy API
.post(
`${CORTEX_API_URL}/v1/engines/${InferenceEngine.cortex_llamacpp}/default?version=${CORTEX_ENGINE_VERSION}&variant=${variant}`,
{
json: {
version: CORTEX_ENGINE_VERSION,
variant,
},
}
)
.then(() => {})
)
}
/**
* Clean cortex processes
* @returns
*/
private clean(): Promise<any> {
private async clean(): Promise<any> {
return ky
.delete(`${CORTEX_API_URL}/processmanager/destroy`, {
timeout: 2000, // maximum 2 seconds
@ -301,6 +265,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
this.socket.addEventListener('message', (event) => {
const data = JSON.parse(event.data)
const transferred = data.task.items.reduce(
(acc: number, cur: any) => acc + cur.downloadedBytes,
0
@ -320,9 +285,17 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
transferred: transferred,
total: total,
},
downloadType: data.task.type,
}
)
// Update models list from Hub
if (data.task.type === 'Engine') {
events.emit(EngineEvent.OnEngineUpdate, {
type: DownloadTypes[data.type as keyof typeof DownloadTypes],
percent: percent,
id: data.task.id,
})
} else {
if (data.type === DownloadTypes.DownloadSuccess) {
// Delay for the state update from cortex.cpp
// Just to be sure
@ -332,6 +305,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
})
}, 500)
}
}
})
/**

View File

@ -54,17 +54,6 @@ jest.mock('child_process', () => ({
},
}))
jest.mock('./execute', () => ({
executableCortexFile: () => {
return {
enginePath: 'enginePath',
executablePath: 'executablePath',
cudaVisibleDevices: 'cudaVisibleDevices',
vkVisibleDevices: 'vkVisibleDevices',
}
},
}))
import index from './index'
describe('dispose', () => {

View File

@ -1,6 +1,5 @@
import path from 'path'
import { getJanDataFolderPath, log, SystemInformation } from '@janhq/core/node'
import { engineVariant, executableCortexFile } from './execute'
import { ProcessWatchdog } from './watchdog'
// The HOST address to use for the Nitro subprocess
@ -15,21 +14,12 @@ function run(systemInfo?: SystemInformation): Promise<any> {
log(`[CORTEX]:: Spawning cortex subprocess...`)
return new Promise<void>(async (resolve, reject) => {
let executableOptions = executableCortexFile(
// If ngl is not set or equal to 0, run on CPU with correct instructions
systemInfo?.gpuSetting
? {
...systemInfo.gpuSetting,
run_mode: systemInfo.gpuSetting.run_mode,
}
: undefined
)
let gpuVisibleDevices = systemInfo?.gpuSetting?.gpus_in_use.join(',') ?? ''
let binaryName = `cortex-server${process.platform === 'win32' ? '.exe' : ''}`
const binPath = path.join(__dirname, '..', 'bin')
const executablePath = path.join(binPath, binaryName)
// Execute the binary
log(`[CORTEX]:: Spawn cortex at path: ${executableOptions.executablePath}`)
log(`[CORTEX]:: Cortex engine path: ${executableOptions.enginePath}`)
addEnvPaths(executableOptions.enginePath)
log(`[CORTEX]:: Spawn cortex at path: ${executablePath}`)
const dataFolderPath = getJanDataFolderPath()
if (watchdog) {
@ -37,7 +27,7 @@ function run(systemInfo?: SystemInformation): Promise<any> {
}
watchdog = new ProcessWatchdog(
executableOptions.executablePath,
executablePath,
[
'--start-server',
'--port',
@ -48,14 +38,12 @@ function run(systemInfo?: SystemInformation): Promise<any> {
dataFolderPath,
],
{
cwd: executableOptions.enginePath,
env: {
...process.env,
ENGINE_PATH: executableOptions.enginePath,
CUDA_VISIBLE_DEVICES: executableOptions.cudaVisibleDevices,
CUDA_VISIBLE_DEVICES: gpuVisibleDevices,
// Vulkan - Support 1 device at a time for now
...(executableOptions.vkVisibleDevices?.length > 0 && {
GGML_VULKAN_DEVICE: executableOptions.vkVisibleDevices[0],
...(gpuVisibleDevices?.length > 0 && {
GGML_VK_VISIBLE_DEVICES: gpuVisibleDevices,
}),
},
}
@ -96,5 +84,4 @@ export interface CortexProcessInfo {
export default {
run,
dispose,
engineVariant,
}

View File

@ -5,11 +5,7 @@
"module": "esnext",
"strict": true,
"sourceMap": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"declarationDir": "dist/types",
"esModuleInterop": true,
"outDir": "dist",
"importHelpers": true,
"typeRoots": ["node_modules/@types"]

View File

@ -4,26 +4,23 @@
"version": "1.0.1",
"description": "This extension enables fast Groq chat completion API calls",
"main": "dist/index.js",
"engine": "groq",
"module": "dist/module.js",
"author": "Carsen Klock & Jan",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && npm run build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"ulidx": "^2.3.0"
},
@ -37,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -6,10 +6,7 @@
* @module inference-groq-extension/src/index
*/
import { RemoteOAIEngine, SettingComponentProps } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
import { RemoteOAIEngine } from '@janhq/core'
enum Settings {
apiKey = 'groq-api-key',

View File

@ -1,37 +0,0 @@
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
MODULE: JSON.stringify(`${packageJson.name}/${packageJson.module}`),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -9,22 +9,18 @@
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"ulidx": "^2.3.0"
},
@ -38,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -6,10 +6,7 @@
* @module inference-martian-extension/src/index
*/
import { RemoteOAIEngine, SettingComponentProps } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
import { RemoteOAIEngine } from '@janhq/core'
enum Settings {
apiKey = 'martian-api-key',

View File

@ -1,37 +0,0 @@
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -9,24 +9,19 @@
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"path-browserify": "^1.0.1",
"ulidx": "^2.3.0"
},
"engines": {
@ -39,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -8,9 +8,6 @@
import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings {
apiKey = 'mistral-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint',

View File

@ -1,42 +0,0 @@
const path = require('path')
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
MODELS: JSON.stringify(modelsJson),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
path: path.resolve(__dirname, 'dist'),
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
fallback: {
path: require.resolve('path-browserify'),
},
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -9,24 +9,19 @@
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"path-browserify": "^1.0.1",
"ulidx": "^2.3.0"
},
"engines": {
@ -39,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -8,9 +8,6 @@
import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings {
apiKey = 'nvidia-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint',

View File

@ -1,42 +0,0 @@
const path = require('path')
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
MODELS: JSON.stringify(modelsJson),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
path: path.resolve(__dirname, 'dist'),
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
fallback: {
path: require.resolve('path-browserify'),
},
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -9,22 +9,18 @@
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"ulidx": "^2.3.0"
},
@ -38,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -8,9 +8,6 @@
import { ModelRuntimeParams, PayloadType, RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
export enum Settings {
apiKey = 'openai-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint',

View File

@ -1,37 +0,0 @@
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -9,23 +9,18 @@
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install",
"sync:core": "cd ../.. && yarn build:core && cd extensions && rm yarn.lock && cd inference-openrouter-extension && yarn && yarn build:publish"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"ts-loader": "^9.5.0"
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"ulidx": "^2.3.0"
},
@ -39,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
import modelsJson from './resources/models.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1,2 @@
declare const SETTINGS: SettingComponentProps[]
declare const MODELS: Model[]

View File

@ -9,9 +9,6 @@
import { RemoteOAIEngine } from '@janhq/core'
import { PayloadType } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings {
apiKey = 'openrouter-api-key',
model = 'openrouter-model',

View File

@ -1,37 +0,0 @@
const webpack = require('webpack')
const packageJson = require('./package.json')
const settingJson = require('./resources/settings.json')
const modelsJson = require('./resources/models.json')
module.exports = {
experiments: { outputModule: true },
entry: './src/index.ts', // Adjust the entry point to match your project's main file
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.DefinePlugin({
MODELS: JSON.stringify(modelsJson),
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(packageJson.engine),
}),
],
output: {
filename: 'index.js', // Adjust the output file name as needed
library: { type: 'module' }, // Specify ESM output format
},
resolve: {
extensions: ['.ts', '.js'],
},
optimization: {
minimize: false,
},
// Add loaders and other configuration as needed for your project
}

View File

@ -4,27 +4,22 @@
"version": "1.0.0",
"description": "This extension enables Nvidia's TensorRT-LLM as an inference engine option",
"main": "dist/index.js",
"module": "dist/module.js",
"engine": "triton_trtllm",
"author": "Jan <service@jan.ai>",
"license": "AGPL-3.0",
"scripts": {
"build": "tsc -b . && webpack --config webpack.config.js",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
"build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"devDependencies": {
"cpx": "^1.5.0",
"rimraf": "^3.0.2",
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0",
"typescript": "5.3.3",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4"
"typescript": "^5.7.2"
},
"dependencies": {
"@janhq/core": "file:../../core",
"@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6",
"rxjs": "^7.8.1",
"ulidx": "^2.3.0"
@ -39,5 +34,9 @@
],
"bundleDependencies": [
"fetch-retry"
]
],
"installConfig": {
"hoistingLimits": "workspaces"
},
"packageManager": "yarn@4.5.3"
}

View File

@ -0,0 +1,16 @@
import { defineConfig } from 'rolldown'
import pkgJson from './package.json' with { type: 'json' }
import settingJson from './resources/settings.json' with { type: 'json' }
export default defineConfig({
input: 'src/index.ts',
output: {
format: 'esm',
file: 'dist/index.js',
},
platform: 'browser',
define: {
SETTINGS: JSON.stringify(settingJson),
ENGINE: JSON.stringify(pkgJson.engine),
},
})

View File

@ -0,0 +1 @@
declare const SETTINGS: SettingComponentProps[]

View File

@ -6,9 +6,8 @@
* @module inference-nvidia-triton-trt-llm-extension/src/index
*/
import { RemoteOAIEngine, SettingComponentProps } from '@janhq/core'
import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
enum Settings {
apiKey = 'tritonllm-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint',

Some files were not shown because too many files have changed in this diff Show More