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

View File

@ -1,4 +1,4 @@
name: Publish plugin models Package to npmjs name: Publish core Package to npmjs
on: on:
push: push:
tags: ["v[0-9]+.[0-9]+.[0-9]+-core"] tags: ["v[0-9]+.[0-9]+.[0-9]+-core"]
@ -45,7 +45,7 @@ jobs:
node-version: "20.x" node-version: "20.x"
registry-url: "https://registry.npmjs.org" 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 - run: cd core && yarn publish --access public
if: github.event_name == 'push' 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: on:
push: push:
tags: ["v[0-9]+.[0-9]+.[0-9]+-joi"] tags: ["v[0-9]+.[0-9]+.[0-9]+-joi"]
@ -45,7 +45,7 @@ jobs:
node-version: "20.x" node-version: "20.x"
registry-url: "https://registry.npmjs.org" 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 - run: cd joi && yarn publish --access public
if: github.event_name == 'push' if: github.event_name == 'push'

5
.gitignore vendored
View File

@ -8,7 +8,6 @@ error.log
node_modules node_modules
*.tgz *.tgz
!charts/server/charts/*.tgz !charts/server/charts/*.tgz
yarn.lock
dist dist
build build
.DS_Store .DS_Store
@ -48,3 +47,7 @@ coverage
test_results.html test_results.html
*.tsbuildinfo *.tsbuildinfo
electron/shared/** 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: all:
@echo "Specify a target to run" @echo "Specify a target to run"
# Builds the UI kit # Config yarn version
build-joi:
ifeq ($(OS),Windows_NT) config-yarn:
cd joi && yarn config set network-timeout 300000 && yarn install && yarn build corepack enable
else corepack prepare yarn@4.5.3 --activate
cd joi && yarn install && yarn build yarn --version
endif yarn config set -H enableImmutableInstalls false
# Installs yarn dependencies and builds core and extensions # Installs yarn dependencies and builds core and extensions
install-and-build: build-joi install-and-build: config-yarn
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
yarn config set network-timeout 300000 echo "skip"
endif endif
yarn global add turbo@1.13.2 yarn install
yarn build:joi
yarn build:core yarn build:core
yarn build:server yarn build:server
yarn install
yarn build:extensions yarn build:extensions
check-file-counts: install-and-build check-file-counts: install-and-build
@ -117,9 +117,8 @@ build: check-file-counts
clean: clean:
ifeq ($(OS),Windows_NT) 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 node_modules, .next, dist, build, out, .turbo, .yarn -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 package-lock.json, tsconfig.tsbuildinfo -Recurse -File | Remove-Item -Recurse -Force"
-powershell -Command "Get-ChildItem -Path . -Include yarn.lock -Recurse -File | Remove-Item -Recurse -Force"
-powershell -Command "Remove-Item -Recurse -Force ./pre-install/*.tgz" -powershell -Command "Remove-Item -Recurse -Force ./pre-install/*.tgz"
-powershell -Command "Remove-Item -Recurse -Force ./extensions/*/*.tgz" -powershell -Command "Remove-Item -Recurse -Force ./extensions/*/*.tgz"
-powershell -Command "Remove-Item -Recurse -Force ./electron/pre-install/*.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 "build" -type d -exec rm -rf '{}' +
find . -name "out" -type d -exec rm -rf '{}' + find . -name "out" -type d -exec rm -rf '{}' +
find . -name ".turbo" -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 "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 '{}' + find . -name "package-lock.json" -type f -exec rm -rf '{}' +
rm -rf ./pre-install/*.tgz rm -rf ./pre-install/*.tgz
rm -rf ./extensions/*/*.tgz rm -rf ./extensions/*/*.tgz
@ -146,8 +145,8 @@ else
find . -name "build" -type d -exec rm -rf '{}' + find . -name "build" -type d -exec rm -rf '{}' +
find . -name "out" -type d -exec rm -rf '{}' + find . -name "out" -type d -exec rm -rf '{}' +
find . -name ".turbo" -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 "package-lock.json" -type f -exec rm -rf '{}' +
find . -name "yarn.lock" -type f -exec rm -rf '{}' +
rm -rf ./pre-install/*.tgz rm -rf ./pre-install/*.tgz
rm -rf ./extensions/*/*.tgz rm -rf ./extensions/*/*.tgz
rm -rf ./electron/pre-install/*.tgz rm -rf ./electron/pre-install/*.tgz

View File

@ -1,15 +1,16 @@
{ {
"name": "@janhq/core", "name": "@janhq/core",
"version": "0.1.10", "version": "0.1.10",
"description": "Jan app core lib", "description": "Core library for the Jan AI application framework",
"keywords": [ "keywords": [
"jan", "jan",
"core" "core"
], ],
"homepage": "https://jan.ai", "homepage": "https://jan.ai",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "dist/core.es5.js", "browser": "dist/index.js",
"module": "dist/core.cjs.js", "main": "dist/index.js",
"module": "dist/node/index.cjs.js",
"typings": "dist/types/index.d.ts", "typings": "dist/types/index.d.ts",
"files": [ "files": [
"dist", "dist",
@ -17,13 +18,13 @@
], ],
"author": "Jan <service@jan.ai>", "author": "Jan <service@jan.ai>",
"exports": { "exports": {
".": "./dist/core.es5.js", ".": "./dist/index.js",
"./node": "./dist/node/index.cjs.js" "./node": "./dist/node/index.cjs.js"
}, },
"typesVersions": { "typesVersions": {
"*": { "*": {
".": [ ".": [
"./dist/core.es5.js.map", "./dist/index.js.map",
"./dist/types/index.d.ts" "./dist/types/index.d.ts"
], ],
"node": [ "node": [
@ -36,25 +37,25 @@
"lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'", "lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'",
"test": "jest", "test": "jest",
"prebuild": "rimraf dist", "prebuild": "rimraf dist",
"build": "tsc --module commonjs && rollup -c rollup.config.ts", "build": "tsc -p . && rolldown -c rolldown.config.mjs"
"start": "rollup -c rollup.config.ts -w"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-replace": "^5.0.5", "@npmcli/arborist": "^7.1.0",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.14",
"@types/node": "^20.11.4", "@types/node": "^22.10.0",
"@types/pacote": "^11.1.7",
"@types/request": "^2.48.12",
"electron": "33.2.1",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-plugin-jest": "^27.9.0", "eslint-plugin-jest": "^27.9.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",
"jest-runner": "^29.7.0", "jest-runner": "^29.7.0",
"pacote": "^21.0.0",
"request": "^2.88.2",
"request-progress": "^3.0.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.38.5", "rolldown": "1.0.0-beta.1",
"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",
"ts-jest": "^29.2.5", "ts-jest": "^29.2.5",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "^5.3.3" "typescript": "^5.3.3"
@ -62,5 +63,6 @@
"dependencies": { "dependencies": {
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"ulidx": "^2.3.0" "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 * Execute a extension module function in main process
@ -9,11 +14,12 @@ import { DownloadRequest, FileStat, NetworkConfig, SystemInformation } from '../
* @returns Promise<any> * @returns Promise<any>
* *
*/ */
const executeOnMain: (extension: string, method: string, ...args: any[]) => Promise<any> = ( const executeOnMain: (
extension, extension: string,
method, method: string,
...args ...args: any[]
) => globalThis.core?.api?.invokeExtensionFunc(extension, method, ...args) ) => 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. * 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. * @returns {Promise<any>} A promise that resolves when the file is downloaded.
*/ */
const downloadFile: (downloadRequest: DownloadRequest, network?: NetworkConfig) => Promise<any> = ( const downloadFile: (
downloadRequest, downloadRequest: DownloadRequest,
network network?: NetworkConfig
) => globalThis.core?.api?.downloadFile(downloadRequest, network) ) => Promise<any> = (downloadRequest, network) =>
globalThis.core?.api?.downloadFile(downloadRequest, network)
/** /**
* Aborts the download of a specific file. * 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. * @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. * 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. * @param path - The file path to retrieve dirname.
* @returns {Promise<string>} A promise that resolves the 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. * Retrieve the basename from an url.
* @param path - The path to retrieve. * @param path - The path to retrieve.
* @returns {Promise<string>} A promise that resolves with the basename. * @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. * 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. * @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. * Gets the user's home path.
* @returns return 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. * 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. * @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) => const isSubdirectory: (from: string, to: string) => Promise<boolean> = (
globalThis.core.api?.isSubdirectory(from, to) from: string,
to: string
) => globalThis.core.api?.isSubdirectory(from, to)
/** /**
* Get system information * Get system information
@ -159,5 +173,4 @@ export {
systemInformation, systemInformation,
showToast, showToast,
dirName, dirName,
FileStat,
} }

View File

@ -11,6 +11,7 @@ export enum ExtensionTypeEnum {
Model = 'model', Model = 'model',
SystemMonitoring = 'systemMonitoring', SystemMonitoring = 'systemMonitoring',
HuggingFace = 'huggingFace', HuggingFace = 'huggingFace',
Engine = 'engine',
} }
export interface ExtensionType { 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. * Base AI Engines.
*/ */
export * from './engines' export * from './engines'
/**
* Engines Management
*/
export * from './enginesManagement'

View File

@ -4,16 +4,6 @@ jest.mock('../../helper', () => ({
})) }))
import { App } from './app' 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', () => { it('should correctly retrieve basename', () => {
const app = new App() const app = new App()
const result = app.baseName('/path/to/file.txt') const result = app.baseName('/path/to/file.txt')
@ -23,7 +13,8 @@ it('should correctly retrieve basename', () => {
it('should correctly identify subdirectories', () => { it('should correctly identify subdirectories', () => {
const app = new App() const app = new App()
const basePath = process.platform === 'win32' ? 'C:\\path\\to' : '/path/to' 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) const result = app.isSubdirectory(basePath, subPath)
expect(result).toBe(true) expect(result).toBe(true)
}) })
@ -31,7 +22,8 @@ it('should correctly identify subdirectories', () => {
it('should correctly join multiple paths', () => { it('should correctly join multiple paths', () => {
const app = new App() const app = new App()
const result = app.joinPath(['path', 'to', 'file']) 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) 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 () => { it('should retrieve the directory name when using file protocol', async () => {
const app = new App() const app = new App()
const path = 'file:/models/file.txt' 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. * 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 from - The path to check.
* @param to - The directory to check against. * @param to - The directory to check against.
*
* @returns {Promise<boolean>} - A promise that resolves with the result.
*/ */
isSubdirectory(from: any, to: any) { isSubdirectory(from: any, to: any) {
const rel = relative(from, to) const rel = relative(from, to)
@ -79,26 +76,4 @@ export class App implements Processor {
async updateAppConfiguration(args: any) { async updateAppConfiguration(args: any) {
await updateAppConfiguration(args) 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} * @type {string}
*/ */
get specifier() { 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() { async getManifest() {
// Get the package's manifest (package.json object) // Get the package's manifest (package.json object)
try { try {
await import('pacote').then((pacote) => { const pacote = require('pacote')
return pacote.manifest(this.specifier, this.installOptions).then((mnf) => { return pacote
.manifest(this.specifier, this.installOptions)
.then((mnf: any) => {
// set the Package properties based on the it's manifest // set the Package properties based on the it's manifest
this.name = mnf.name this.name = mnf.name
this.productName = mnf.productName as string | undefined this.productName = mnf.productName as string | undefined
@ -84,9 +89,10 @@ export default class Extension {
this.main = mnf.main this.main = mnf.main
this.description = mnf.description this.description = mnf.description
}) })
})
} catch (error) { } 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 return true
@ -103,10 +109,13 @@ export default class Extension {
await this.getManifest() await this.getManifest()
// Install the package in a child folder of the given folder // Install the package in a child folder of the given folder
const pacote = await import('pacote') const pacote = require('pacote')
await pacote.extract( await pacote.extract(
this.specifier, this.specifier,
join(ExtensionManager.instance.getExtensionsPath() ?? '', this.name ?? ''), join(
ExtensionManager.instance.getExtensionsPath() ?? '',
this.name ?? ''
),
this.installOptions 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. * @returns the latest available version if a new version is available or false if not.
*/ */
async isUpdateAvailable() { async isUpdateAvailable() {
return import('pacote').then((pacote) => { const pacote = require('pacote')
if (this.origin) { 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 return mnf.version !== this.version ? mnf.version : false
}) })
} }
})
} }
/** /**

View File

@ -27,7 +27,10 @@ export enum NativeRoute {
quickAskSizeUpdated = 'quickAskSizeUpdated', quickAskSizeUpdated = 'quickAskSizeUpdated',
ackDeepLink = 'ackDeepLink', ackDeepLink = 'ackDeepLink',
factoryReset = 'factoryReset' factoryReset = 'factoryReset',
startServer = 'startServer',
stopServer = 'stopServer',
} }
/** /**
@ -41,8 +44,6 @@ export enum AppRoute {
dirName = 'dirName', dirName = 'dirName',
isSubdirectory = 'isSubdirectory', isSubdirectory = 'isSubdirectory',
baseName = 'baseName', baseName = 'baseName',
startServer = 'startServer',
stopServer = 'stopServer',
log = 'log', log = 'log',
systemInformation = 'systemInformation', systemInformation = 'systemInformation',
showToast = 'showToast', 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 './miscellaneous'
export * from './api' export * from './api'
export * from './setting' export * from './setting'
export * from './engine'

View File

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

View File

@ -58,5 +58,5 @@
"prettier": "^3.2.5", "prettier": "^3.2.5",
"typescript": "^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() ModuleManager.instance.clearImportedModules()
return createUserSpace().then(migrate).then(setupExtensions) 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": { "scripts": {
"lint": "eslint . --ext \".js,.jsx,.ts,.tsx\"", "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\"", "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 .", "compile": "tsc -p .",
"start": "electron .", "start": "electron .",
"build": "yarn copy:assets && run-script-os", "build": "yarn copy:assets && run-script-os",
@ -98,22 +100,23 @@
}, },
"dependencies": { "dependencies": {
"@alumna/reflect": "^1.1.3", "@alumna/reflect": "^1.1.3",
"@janhq/core": "link:./core", "@janhq/core": "link:../core",
"@janhq/server": "link:./server", "@janhq/server": "link:../server",
"@kirillvakalov/nut-tree__nut-js": "4.2.1-2",
"@npmcli/arborist": "^7.1.0", "@npmcli/arborist": "^7.1.0",
"electron-store": "^8.1.0", "electron-store": "^8.1.0",
"electron-updater": "^6.1.7", "electron-updater": "^6.1.7",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"node-fetch": "2", "node-fetch": "2",
"pacote": "^17.0.4", "pacote": "^21.0.0",
"request": "^2.88.2", "request": "^2.88.2",
"request-progress": "^3.0.0", "request-progress": "^3.0.0",
"ulidx": "^2.3.0", "ulidx": "^2.3.0"
"@kirillvakalov/nut-tree__nut-js": "4.2.1-2"
}, },
"devDependencies": { "devDependencies": {
"@electron/notarize": "^2.5.0", "@electron/notarize": "^2.5.0",
"@playwright/test": "^1.38.1", "@playwright/test": "^1.38.1",
"@reportportal/agent-js-playwright": "^5.1.7",
"@types/npmcli__arborist": "^5.6.4", "@types/npmcli__arborist": "^5.6.4",
"@types/pacote": "^11.1.7", "@types/pacote": "^11.1.7",
"@types/request": "^2.48.12", "@types/request": "^2.48.12",
@ -129,9 +132,10 @@
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"run-script-os": "^1.1.6", "run-script-os": "^1.1.6",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"@reportportal/agent-js-playwright": "^5.1.7" "xvfb-maybe": "^0.2.1"
}, },
"installConfig": { "installConfig": {
"hoistingLimits": "workspaces" "hoistingLimits": "workspaces"
} },
"packageManager": "yarn@4.5.3"
} }

View File

@ -36,7 +36,7 @@ export async function setupElectron() {
expect(appInfo).toBeTruthy() expect(appInfo).toBeTruthy()
electronApp = await electron.launch({ 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 executablePath: appInfo.executable, // path to the Electron executable
// recordVideo: { dir: Constants.VIDEO_DIR }, // Specify the directory for video recordings // 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", "name": "@janhq/assistant-extension",
"productName": "Jan Assistant", "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", "description": "This extension enables assistants, including Jan, a default assistant that can call all downloaded models",
"main": "dist/index.js", "main": "dist/index.js",
"node": "dist/node/index.js", "node": "dist/node/index.js",
@ -9,33 +9,28 @@
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "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", "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-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 && tsc --module commonjs && rollup -c rollup.config.ts", "build": "yarn clean:modules && rolldown -c rolldown.config.mjs",
"build:publish:linux": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install", "build:publish:linux": "rimraf *.tgz --glob || true && 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: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 && yarn build && 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:publish": "run-script-os",
"build:dev": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
}, },
"devDependencies": { "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", "@types/pdf-parse": "^1.1.4",
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.38.5", "rolldown": "1.0.0-beta.1",
"rollup-plugin-define": "^1.0.1", "run-script-os": "^1.1.6",
"rollup-plugin-sourcemaps": "^0.6.3", "typescript": "^5.3.3"
"rollup-plugin-typescript2": "^0.36.0",
"typescript": "^5.3.3",
"run-script-os": "^1.1.6"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"@langchain/community": "0.0.13", "@langchain/community": "0.0.13",
"hnswlib-node": "^1.4.2", "hnswlib-node": "^1.4.2",
"langchain": "^0.0.214", "langchain": "^0.0.214",
"node-gyp": "^11.0.0",
"pdf-parse": "^1.1.1", "pdf-parse": "^1.1.1",
"ts-loader": "^9.5.0" "ts-loader": "^9.5.0"
}, },
@ -47,5 +42,9 @@
"bundleDependencies": [ "bundleDependencies": [
"@janhq/core", "@janhq/core",
"hnswlib-node" "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 { retrieval } from './retrieval'
import path from 'path' import path from 'path'

View File

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

View File

@ -8,8 +8,8 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"test": "jest", "test": "jest",
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
}, },
"exports": { "exports": {
".": "./dist/index.js", ".": "./dist/index.js",
@ -18,12 +18,12 @@
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0", "ts-loader": "^9.5.0",
"webpack": "^5.88.2", "typescript": "^5.7.2"
"webpack-cli": "^5.1.4"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"ky": "^1.7.2", "ky": "^1.7.2",
"p-queue": "^8.0.1" "p-queue": "^8.0.1"
}, },
@ -35,5 +35,9 @@
"package.json", "package.json",
"README.md" "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 API_URL: string
declare const SOCKET_URL: string declare const SOCKET_URL: string
@ -11,4 +9,3 @@ declare global {
core?: Core | undefined core?: Core | undefined
electronAPI?: any | 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 { describe, expect, it } from '@jest/globals'
import { engineVariant, executableCortexFile } from './execute' import engine from './index'
import { GpuSetting } from '@janhq/core/node' import { GpuSetting } from '@janhq/core/node'
import { cpuInfo } from 'cpu-instructions' import { cpuInfo } from 'cpu-instructions'
import { fork } from 'child_process' import { fork } from 'child_process'
@ -62,20 +62,9 @@ describe('test executable cortex file', () => {
Object.defineProperty(process, 'arch', { Object.defineProperty(process, 'arch', {
value: 'arm64', 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) mockFork.mockReturnValue(mockProcess)
expect(engineVariant(testSettings)).resolves.toEqual('mac-arm64') expect(engine.engineVariant(testSettings)).resolves.toEqual('mac-arm64')
}) })
it('executes on MacOS', () => { it('executes on MacOS', () => {
@ -99,18 +88,7 @@ describe('test executable cortex file', () => {
value: 'x64', value: 'x64',
}) })
expect(executableCortexFile(testSettings)).toEqual( expect(engine.engineVariant(testSettings)).resolves.toEqual('mac-amd64')
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath:
originalPlatform === 'darwin'
? expect.stringContaining(`cortex-server`)
: expect.anything(),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant(testSettings)).resolves.toEqual('mac-amd64')
}) })
it('executes on Windows CPU', () => { it('executes on Windows CPU', () => {
@ -131,15 +109,7 @@ describe('test executable cortex file', () => {
} }
mockFork.mockReturnValue(mockProcess) mockFork.mockReturnValue(mockProcess)
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant()).resolves.toEqual('windows-amd64-avx')
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant()).resolves.toEqual('windows-amd64-avx')
}) })
it('executes on Windows Cuda 11', () => { it('executes on Windows Cuda 11', () => {
@ -176,15 +146,8 @@ describe('test executable cortex file', () => {
send: jest.fn(), send: jest.fn(),
} }
mockFork.mockReturnValue(mockProcess) mockFork.mockReturnValue(mockProcess)
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({ expect(engine.engineVariant(settings)).resolves.toEqual(
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
'windows-amd64-avx2-cuda-11-7' 'windows-amd64-avx2-cuda-11-7'
) )
}) })
@ -221,15 +184,8 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({ expect(engine.engineVariant(settings)).resolves.toEqual(
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
'windows-amd64-noavx-cuda-12-0' 'windows-amd64-noavx-cuda-12-0'
) )
mockFork.mockReturnValue({ mockFork.mockReturnValue({
@ -240,7 +196,7 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(engineVariant(settings)).resolves.toEqual( expect(engine.engineVariant(settings)).resolves.toEqual(
'windows-amd64-avx2-cuda-12-0' 'windows-amd64-avx2-cuda-12-0'
) )
}) })
@ -261,15 +217,8 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({ expect(engine.engineVariant()).resolves.toEqual('linux-amd64-noavx')
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant()).resolves.toEqual('linux-amd64-noavx')
}) })
it('executes on Linux Cuda 11', () => { it('executes on Linux Cuda 11', () => {
@ -306,15 +255,9 @@ describe('test executable cortex file', () => {
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant(settings)).resolves.toBe(
expect.objectContaining({ 'linux-amd64-avx2-cuda-11-7'
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
) )
expect(engineVariant(settings)).resolves.toBe('linux-amd64-avx2-cuda-11-7')
}) })
it('executes on Linux Cuda 12', () => { it('executes on Linux Cuda 12', () => {
@ -349,15 +292,8 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual(
expect.objectContaining({ expect(engine.engineVariant(settings)).resolves.toEqual(
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
'linux-amd64-avx2-cuda-12-0' 'linux-amd64-avx2-cuda-12-0'
) )
}) })
@ -383,16 +319,7 @@ describe('test executable cortex file', () => {
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant(settings)).resolves.toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant(settings)).resolves.toEqual(
`linux-amd64-${instruction}` `linux-amd64-${instruction}`
) )
}) })
@ -416,15 +343,7 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant(settings)).resolves.toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '',
vkVisibleDevices: '',
})
)
expect(engineVariant(settings)).resolves.toEqual(
`windows-amd64-${instruction}` `windows-amd64-${instruction}`
) )
}) })
@ -465,15 +384,7 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant(settings)).resolves.toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server.exe`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
`windows-amd64-${instruction === 'avx512' || instruction === 'avx2' ? 'avx2' : 'noavx'}-cuda-12-0` `windows-amd64-${instruction === 'avx512' || instruction === 'avx2' ? 'avx2' : 'noavx'}-cuda-12-0`
) )
}) })
@ -514,15 +425,7 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant(settings)).resolves.toEqual(
expect.objectContaining({
enginePath: expect.stringContaining('shared'),
executablePath: expect.stringContaining(`cortex-server`),
cudaVisibleDevices: '0',
vkVisibleDevices: '0',
})
)
expect(engineVariant(settings)).resolves.toEqual(
`linux-amd64-${instruction === 'avx512' || instruction === 'avx2' ? 'avx2' : 'noavx'}-cuda-12-0` `linux-amd64-${instruction === 'avx512' || instruction === 'avx2' ? 'avx2' : 'noavx'}-cuda-12-0`
) )
}) })
@ -564,50 +467,8 @@ describe('test executable cortex file', () => {
}), }),
send: jest.fn(), send: jest.fn(),
}) })
expect(executableCortexFile(settings)).toEqual( expect(engine.engineVariant(settings)).resolves.toEqual(
expect.objectContaining({ `linux-amd64-vulkan`
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: '',
})
) )
}) })
}) })

View File

@ -1,13 +1,13 @@
import * as path from 'path' 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 { 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. * The GPU runMode that will be set - either 'vulkan', 'cuda', or empty for cpu.
* @param settings * @param settings
@ -37,14 +37,6 @@ const os = (): string => {
: 'linux-amd64' : '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'. * The CUDA version that will be set - either '11-7' or '12-0'.
* @param settings * @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. * Find which variant to run based on the current platform.
*/ */
export const engineVariant = async ( const engineVariant = async (gpuSetting?: GpuSetting): Promise<string> => {
gpuSetting?: GpuSetting
): Promise<string> => {
const cpuInstruction = await cpuInstructions() const cpuInstruction = await cpuInstructions()
log(`[CORTEX]: CPU instruction: ${cpuInstruction}`) log(`[CORTEX]: CPU instruction: ${cpuInstruction}`)
let engineVariant = [ let engineVariant = [
@ -135,3 +107,45 @@ export const engineVariant = async (
log(`[CORTEX]: Engine variant: ${engineVariant}`) log(`[CORTEX]: Engine variant: ${engineVariant}`)
return 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", "version": "1.0.3",
"description": "This extension enables Anthropic chat completion API calls", "description": "This extension enables Anthropic chat completion API calls",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/module.js",
"engine": "anthropic", "engine": "anthropic",
"author": "Jan <service@jan.ai>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"test": "jest test", "test": "jest test",
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install", "build:publish": "rimraf *.tgz --glob || true && 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"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
@ -40,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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 { PayloadType } from '@janhq/core'
import { ChatCompletionRole } from '@janhq/core' import { ChatCompletionRole } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
export enum Settings { export enum Settings {
apiKey = 'anthropic-api-key', apiKey = 'anthropic-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint', 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>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install", "build:publish": "rimraf *.tgz --glob || true && 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"
}, },
"exports": { "exports": {
".": "./dist/index.js", ".": "./dist/index.js",
@ -20,12 +19,12 @@
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
@ -39,5 +38,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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 { PayloadType } from '@janhq/core'
import { ChatCompletionRole } from '@janhq/core' import { ChatCompletionRole } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings { enum Settings {
apiKey = 'cohere-api-key', apiKey = 'cohere-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint', 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 "${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-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 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 elif [ "$OS_TYPE" == "Darwin" ]; then
# macOS downloads # macOS downloads

View File

@ -9,12 +9,12 @@
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"test": "jest", "test": "jest",
"build": "tsc --module commonjs && rollup -c rollup.config.ts", "build": "rolldown -c rolldown.config.mjs",
"downloadcortex:linux:darwin": "./download.sh", "downloadcortex:linux:darwin": "./download.sh",
"downloadcortex:win32": "download.bat", "downloadcortex:win32": "download.bat",
"downloadcortex": "run-script-os", "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: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 && yarn build && npm run downloadcortex && 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" "build:publish": "run-script-os"
}, },
"exports": { "exports": {
@ -22,12 +22,7 @@
"./main": "./dist/node/index.cjs.js" "./main": "./dist/node/index.cjs.js"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-typescript": "^7.24.1",
"@jest/globals": "^29.7.0", "@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/decompress": "^4.2.7",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/node": "^20.11.4", "@types/node": "^20.11.4",
@ -37,17 +32,13 @@
"download-cli": "^1.1.1", "download-cli": "^1.1.1",
"jest": "^29.7.0", "jest": "^29.7.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.38.5", "rolldown": "1.0.0-beta.1",
"rollup-plugin-define": "^1.0.1",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"run-script-os": "^1.1.6", "run-script-os": "^1.1.6",
"ts-jest": "^29.1.2", "ts-jest": "^29.1.2",
"typescript": "^5.3.3" "typescript": "^5.3.3"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"cpu-instructions": "^0.0.13",
"decompress": "^4.2.1", "decompress": "^4.2.1",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ky": "^1.7.2", "ky": "^1.7.2",
@ -69,7 +60,10 @@
"tcp-port-used", "tcp-port-used",
"fetch-retry", "fetch-retry",
"@janhq/core", "@janhq/core",
"decompress", "decompress"
"cpu-instructions" ],
] "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_API_URL: string
declare const CORTEX_SOCKET_URL: string declare const CORTEX_SOCKET_URL: string
declare const CORTEX_ENGINE_VERSION: string declare const CORTEX_ENGINE_VERSION: string
declare const SETTINGS: Array<any> declare const SETTINGS: object[]
declare const MODELS: Array<any> declare const MODELS: object[]
/**
* The response from the initModel function.
* @property error - An error message if the model fails to load.
*/
interface ModelOperationResponse {
error?: any
modelFile?: string
}

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 { import {
Model, Model,
executeOnMain, executeOnMain,
EngineEvent,
systemInformation, systemInformation,
joinPath, joinPath,
LocalOAIEngine, LocalOAIEngine,
@ -18,9 +19,7 @@ import {
fs, fs,
events, events,
ModelEvent, ModelEvent,
SystemInformation,
dirName, dirName,
AppConfigurationEventName,
} from '@janhq/core' } from '@janhq/core'
import PQueue from 'p-queue' import PQueue from 'p-queue'
import ky from 'ky' import ky from 'ky'
@ -112,21 +111,11 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
const systemInfo = await systemInformation() const systemInfo = await systemInformation()
this.queue.add(() => executeOnMain(NODE, 'run', systemInfo)) this.queue.add(() => executeOnMain(NODE, 'run', systemInfo))
this.queue.add(() => this.healthz()) this.queue.add(() => this.healthz())
this.queue.add(() => this.setDefaultEngine(systemInfo))
this.subscribeToEvents() this.subscribeToEvents()
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
this.clean() 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() { async onUnload() {
@ -236,7 +225,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
* Do health check on cortex.cpp * Do health check on cortex.cpp
* @returns * @returns
*/ */
private healthz(): Promise<void> { private async healthz(): Promise<void> {
return ky return ky
.get(`${CORTEX_API_URL}/healthz`, { .get(`${CORTEX_API_URL}/healthz`, {
retry: { retry: {
@ -248,36 +237,11 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
.then(() => {}) .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 * Clean cortex processes
* @returns * @returns
*/ */
private clean(): Promise<any> { private async clean(): Promise<any> {
return ky return ky
.delete(`${CORTEX_API_URL}/processmanager/destroy`, { .delete(`${CORTEX_API_URL}/processmanager/destroy`, {
timeout: 2000, // maximum 2 seconds timeout: 2000, // maximum 2 seconds
@ -301,6 +265,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
this.socket.addEventListener('message', (event) => { this.socket.addEventListener('message', (event) => {
const data = JSON.parse(event.data) const data = JSON.parse(event.data)
const transferred = data.task.items.reduce( const transferred = data.task.items.reduce(
(acc: number, cur: any) => acc + cur.downloadedBytes, (acc: number, cur: any) => acc + cur.downloadedBytes,
0 0
@ -320,9 +285,17 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
transferred: transferred, transferred: transferred,
total: total, 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) { if (data.type === DownloadTypes.DownloadSuccess) {
// Delay for the state update from cortex.cpp // Delay for the state update from cortex.cpp
// Just to be sure // Just to be sure
@ -332,6 +305,7 @@ export default class JanInferenceCortexExtension extends LocalOAIEngine {
}) })
}, 500) }, 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' import index from './index'
describe('dispose', () => { describe('dispose', () => {

View File

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

View File

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

View File

@ -4,26 +4,23 @@
"version": "1.0.1", "version": "1.0.1",
"description": "This extension enables fast Groq chat completion API calls", "description": "This extension enables fast Groq chat completion API calls",
"main": "dist/index.js", "main": "dist/index.js",
"engine": "groq",
"module": "dist/module.js", "module": "dist/module.js",
"author": "Carsen Klock & Jan", "author": "Carsen Klock & Jan",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && npm run build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
@ -37,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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 * @module inference-groq-extension/src/index
*/ */
import { RemoteOAIEngine, SettingComponentProps } from '@janhq/core' import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings { enum Settings {
apiKey = 'groq-api-key', 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>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
@ -38,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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 * @module inference-martian-extension/src/index
*/ */
import { RemoteOAIEngine, SettingComponentProps } from '@janhq/core' import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings { enum Settings {
apiKey = 'martian-api-key', 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>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"path-browserify": "^1.0.1",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
"engines": { "engines": {
@ -39,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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' import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings { enum Settings {
apiKey = 'mistral-api-key', apiKey = 'mistral-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint', 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>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"path-browserify": "^1.0.1",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
"engines": { "engines": {
@ -39,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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' import { RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings { enum Settings {
apiKey = 'nvidia-api-key', apiKey = 'nvidia-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint', 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>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
@ -38,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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' import { ModelRuntimeParams, PayloadType, RemoteOAIEngine } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
export enum Settings { export enum Settings {
apiKey = 'openai-api-key', apiKey = 'openai-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint', 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>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install", "build:publish": "rimraf *.tgz --glob || true && 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"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"webpack": "^5.88.2", "rolldown": "1.0.0-beta.1",
"webpack-cli": "^5.1.4", "ts-loader": "^9.5.0",
"ts-loader": "^9.5.0" "typescript": "^5.7.2"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
}, },
@ -39,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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 { RemoteOAIEngine } from '@janhq/core'
import { PayloadType } from '@janhq/core' import { PayloadType } from '@janhq/core'
declare const SETTINGS: Array<any>
declare const MODELS: Array<any>
enum Settings { enum Settings {
apiKey = 'openrouter-api-key', apiKey = 'openrouter-api-key',
model = 'openrouter-model', 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", "version": "1.0.0",
"description": "This extension enables Nvidia's TensorRT-LLM as an inference engine option", "description": "This extension enables Nvidia's TensorRT-LLM as an inference engine option",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/module.js", "engine": "triton_trtllm",
"author": "Jan <service@jan.ai>", "author": "Jan <service@jan.ai>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "tsc -b . && webpack --config webpack.config.js", "build": "rolldown -c rolldown.config.mjs",
"build:publish": "rimraf *.tgz --glob && yarn build && npm pack && cpx *.tgz ../../pre-install" "build:publish": "rimraf *.tgz --glob || true && yarn build && npm pack && cpx *.tgz ../../pre-install"
},
"exports": {
".": "./dist/index.js",
"./main": "./dist/module.js"
}, },
"devDependencies": { "devDependencies": {
"cpx": "^1.5.0", "cpx": "^1.5.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rolldown": "1.0.0-beta.1",
"ts-loader": "^9.5.0", "ts-loader": "^9.5.0",
"typescript": "5.3.3", "typescript": "^5.7.2"
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4"
}, },
"dependencies": { "dependencies": {
"@janhq/core": "file:../../core", "@janhq/core": "../../core/package.tgz",
"fetch-retry": "^5.0.6", "fetch-retry": "^5.0.6",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"ulidx": "^2.3.0" "ulidx": "^2.3.0"
@ -39,5 +34,9 @@
], ],
"bundleDependencies": [ "bundleDependencies": [
"fetch-retry" "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 * @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 { enum Settings {
apiKey = 'tritonllm-api-key', apiKey = 'tritonllm-api-key',
chatCompletionsEndPoint = 'chat-completions-endpoint', chatCompletionsEndPoint = 'chat-completions-endpoint',

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