diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0955e546cb5019c4c146e619bcab190cc80a60bc
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: 'github-actions'
+ directory: '/'
+ schedule:
+ interval: 'weekly'
+ - package-ecosystem: 'npm'
+ directory: '/'
+ schedule:
+ interval: 'weekly'
diff --git a/.github/renovate.json b/.github/renovate.json
new file mode 100644
index 0000000000000000000000000000000000000000..ba5d6177e2077cce60788128b7766405acbc2c49
--- /dev/null
+++ b/.github/renovate.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": ["config:base"],
+ "timezone": "Asia/Shanghai",
+ "enabledManagers": ["npm"],
+ "groupName": "opensumi packages",
+ "packageRules": [
+ {
+ "packagePatterns": ["*"],
+ "excludePackagePatterns": ["^@opensumi/ide-"],
+ "enabled": false
+ }
+ ]
+ }
+
\ No newline at end of file
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a2df09a5c9b7a8a381475382475ee14a00aee2f3
--- /dev/null
+++ b/.github/workflows/package.yml
@@ -0,0 +1,90 @@
+name: Package
+
+# Cancel prev CI if new commit come
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ - v*.*
+ pull_request:
+ branches:
+ - main
+ - v*.*
+ paths:
+ - 'packages/**'
+ - package.json
+ - yarn.lock
+
+jobs:
+ build:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [macos-latest]
+ node-version: [20.x]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ - name: Get yarn cache directory path
+ id: yarn_cache_dir_path
+ run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
+
+ - uses: actions/cache@v4
+ id: yarn_cache
+ with:
+ path: ${{ steps.yarn_cache_dir_path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Install
+ run: |
+ yarn install --immutable
+
+ - name: Build
+ run: |
+ yarn run electron-rebuild
+
+ - name: Package
+ run: |
+ yarn run package
+
+ build-windows:
+ runs-on: windows-2019
+ steps:
+ - uses: actions/checkout@v4
+ - name: Use Node.js 20.x
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20.x
+ - name: Get yarn cache directory path
+ id: yarn_cache_dir_path
+ run: echo "dir=$(yarn config get cacheFolder)" >> $Env:GITHUB_OUTPUT
+
+ - uses: actions/cache@v4
+ id: yarn_cache
+ with:
+ path: ${{ steps.yarn_cache_dir_path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+ - name: Install
+ run: |
+ yarn install --immutable
+
+ - name: Build
+ run: |
+ yarn run electron-rebuild
+
+ - name: Package
+ run: |
+ yarn run package
diff --git a/.yarn/releases/yarn-4.3.1.cjs b/.yarn/releases/yarn-4.3.1.cjs
old mode 100644
new mode 100755
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..eaab5d991661d66d3e25697b9eef5f4942dfd0f3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,70 @@
+# Changelog
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+### [0.6.4](https://code.alipay.com/cloud-ide/codefuse-ide/compare/v0.6.3...v0.6.4) (2024-10-16)
+
+
+### Bug Fixes
+
+* set initialized after init ([b95d7b0](https://code.alipay.com/cloud-ide/codefuse-ide/commit/b95d7b04cee5185e6f8d0dcfab4dd481e0be106e))
+
+### [0.6.3](https://code.alipay.com/cloud-ide/codefuse-ide/compare/v0.6.2...v0.6.3) (2024-10-16)
+
+
+### Features
+
+* add minor ([551a6b2](https://code.alipay.com/cloud-ide/codefuse-ide/commit/551a6b2a42618ad530d6713475b5be26f1864b07))
+
+
+### Bug Fixes
+
+* **deps:** update opensumi packages to v3.4.4 ([992b6d6](https://code.alipay.com/cloud-ide/codefuse-ide/commit/992b6d6431454eb036a22ead83d23b84925e4291))
+
+### 0.6.2 (2024-10-11)
+
+
+### Features
+
+* add open logo folder menu ([b5d275c](https://code.alipay.com/cloud-ide/codefuse-ide/commit/b5d275caca26568139436e13f0eba4d5b13dda56))
+* optimaze model config ([09df597](https://code.alipay.com/cloud-ide/codefuse-ide/commit/09df5970d18175431bb89c7af0154152d25956f5))
+* support ai lint and always show inline completions ([9cb41c0](https://code.alipay.com/cloud-ide/codefuse-ide/commit/9cb41c09e64afaa4eaa0cf032e8dcf3081586bca))
+* upgrade opensumi to 3.3.1-next-1725432779.0 ([c000fb2](https://code.alipay.com/cloud-ide/codefuse-ide/commit/c000fb2aae2acea0c79f1242e111f2627fdee573))
+
+
+### Bug Fixes
+
+* **deps:** update opensumi packages to v3.4.0 ([fe2b072](https://code.alipay.com/cloud-ide/codefuse-ide/commit/fe2b0723de6ac5d6d01656f692f58848fde018c8))
+* **deps:** update opensumi packages to v3.4.1 ([80ad4eb](https://code.alipay.com/cloud-ide/codefuse-ide/commit/80ad4eb0bfaf8a60f786bcf3acd03573474ac1d0))
+* **deps:** update opensumi packages to v3.4.3 ([edd7e5c](https://code.alipay.com/cloud-ide/codefuse-ide/commit/edd7e5c1439cdfbcc1204bcf808ddd0419c0dd2c))
+* quit app after setTimeout ([f53684f](https://code.alipay.com/cloud-ide/codefuse-ide/commit/f53684fa401856aaba0381a4b4e0ba3306e24f35))
+
+### 0.6.1 (2024-09-29)
+
+
+### Features
+
+* add open logo folder menu ([b5d275c](https://code.alipay.com/cloud-ide/codefuse-ide/commit/b5d275caca26568139436e13f0eba4d5b13dda56))
+* optimaze model config ([09df597](https://code.alipay.com/cloud-ide/codefuse-ide/commit/09df5970d18175431bb89c7af0154152d25956f5))
+* support ai lint and always show inline completions ([9cb41c0](https://code.alipay.com/cloud-ide/codefuse-ide/commit/9cb41c09e64afaa4eaa0cf032e8dcf3081586bca))
+* upgrade opensumi to 3.3.1-next-1725432779.0 ([c000fb2](https://code.alipay.com/cloud-ide/codefuse-ide/commit/c000fb2aae2acea0c79f1242e111f2627fdee573))
+
+
+### Bug Fixes
+
+* **deps:** update opensumi packages to v3.4.0 ([fe2b072](https://code.alipay.com/cloud-ide/codefuse-ide/commit/fe2b0723de6ac5d6d01656f692f58848fde018c8))
+* **deps:** update opensumi packages to v3.4.1 ([80ad4eb](https://code.alipay.com/cloud-ide/codefuse-ide/commit/80ad4eb0bfaf8a60f786bcf3acd03573474ac1d0))
+* quit app after setTimeout ([f53684f](https://code.alipay.com/cloud-ide/codefuse-ide/commit/f53684fa401856aaba0381a4b4e0ba3306e24f35))
+
+# [0.6.0](https://code.alipay.com/cloud-ide/codefuse-ide/compare/0.5.0...0.6.0) (2024-09-29)
+
+
+### Bug Fixes
+
+* **deps:** update opensumi packages to v3.4.0 ([fe2b072](https://code.alipay.com/cloud-ide/codefuse-ide/commits/fe2b0723de6ac5d6d01656f692f58848fde018c8))
+
+
+### Features
+
+* add open logo folder menu ([b5d275c](https://code.alipay.com/cloud-ide/codefuse-ide/commits/b5d275caca26568139436e13f0eba4d5b13dda56))
+* support ai lint and always show inline completions ([9cb41c0](https://code.alipay.com/cloud-ide/codefuse-ide/commits/9cb41c09e64afaa4eaa0cf032e8dcf3081586bca))
diff --git a/README.md b/README.md
index 5c943d697d78716a240fbb5eaa36a677f4605ff2..0c6681b0d6dd3e49e293b69ef2f964bc42303ec4 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,21 @@
-
NCTI IDE
+# QSemOS IDE
+QSemOS IDE基于开源[codefuse-ide](https://github.com/codefuse-ai/codefuse-ide)作为基础,同时在openEuler社区将IDE开源分享。我们结合嵌入式领域知识和CodeFuse IDE的能力(AI原生、大模型接入、VS Code插件兼容、多平台兼容、模块化、易扩展),持续对QSemOS IDE进行迭代,打造行业内好用的嵌入式集成开发环境。
-NCTI IDE based on CodeFuse and OpenSumi.
-
+## 项目计划
+QSemOS IDE目前已经发布基于VS Code的插件[QSemOS-plugin](https://gitee.com/src-oepkgs/QSemOS-plugin),满足嵌入式开发流程的需要。基于Codefuse IDE的项目计划,规划迭代版本周期为6个月,包括一系列嵌入式开发领域的功能。版本发布后,我们更新下一个版本的项目计划。
-[![Discussions][discussions-image]][discussions-url]
+我们的工作重点和相关规划内容包括:
+- [ ] 逐步完成原插件功能向codefuse-ide迁移 <--:running: 2024年11月
+- [ ] 新建工程(工程向导)优化
+- [ ] 混合部署方案整合
+- [ ] 资源管理
+- [ ] 调试功能增强
+- [ ] 管维平台
-[discussions-image]: https://img.shields.io/badge/discussions-on%20github-blue
-[discussions-url]: https://gitee.com/src-openeuler/botron-platform/issues
+## 协作
+我们乐意听取社区的意见,帮助产品更新和迭代,打造真正好用的嵌入式IDE :violin:
-## ✨ Features
-- **AI-Native Development Environment**: Enjoy an integrated development environment that leverages AI technologies to enhance productivity and streamline workflows.
-- **Open Model Integration**: Our platform supports the seamless integration of various models, allowing developers to customize and extend functionality according to their needs.
-- **VS Code Extension Compatibility**: Benefit from a rich ecosystem of plugins by ensuring compatibility with VS Code extensions, enabling you to leverage existing tools and resources.
-
-
-## Getting started
-
-### Preparation
-- install Node.js >= 20
-- you can use npmmirror.com to speed up the installation in china
- - `yarn config set -H npmRegistryServer "https://registry.npmmirror.com"`
- - `export ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`
-
-### Start the project
-```bash
-# install dependencies
-yarn
-# rebuild native dependencies for electron
-yarn run electron-rebuild
-# start project
-yarn run start
-```
-
-## Links
-
-- **CodeFuse**: https://codefuse.ai
-- **OpenSumi**: https://opensumi.com
+# 参考链接
+- CodeFuse: https://codefuse.ai
+- OpenSumi: https://opensumi.com
\ No newline at end of file
diff --git a/botron-platform.spec b/botron-platform.spec
index df8e598cb724608113e05e79c1e6653d499c0443..f835696ab5cc84ff08016b93c7ccfc6d46e553cb 100644
--- a/botron-platform.spec
+++ b/botron-platform.spec
@@ -2,12 +2,12 @@
Name: botron-platform
Version: 0.0.1
-Release: 27
+Release: 31
Summary: ncti-ide
License: Apache 2.0
URL: https://gitee.com/botron-platform/ncti-ide
Source0: ncti-ide.tar
-BuildRequires: nodejs-yarn libsecret-devel
+BuildRequires: nodejs-yarn libsecret-devel dpkg fakeroot
%description
国创IDE基座
@@ -36,6 +36,14 @@ yarn run make
%doc
%changelog
+* Thu Nov 14 2024 zhongxiangxiang1122 - 0.0.1-31
+- change the icons
+* Mon Nov 11 2024 zhongxiangxiang1122 - 0.0.1-30
+- test
+* Mon Nov 11 2024 zhongxiangxiang1122 - 0.0.1-29
+- test
+* Wed Nov 6 2024 zhongxiangxiang1122 - 0.0.1-28
+- 添加codefuse-ide提交记录,拉取最新代码,更新readme
* Mon Sep 23 2024 zhongxiangxiang1122 - 0.0.1-27
- test
* Mon Sep 23 2024 zhongxiangxiang1122 - 0.0.1-26
diff --git a/forge.config.ts b/forge.config.ts
index af9febf9b00921180dd5be4d07ea02b6a3003f72..ba3ce47f62f930cc7c4480215b494d1add724439 100644
--- a/forge.config.ts
+++ b/forge.config.ts
@@ -77,7 +77,18 @@ const config: ForgeConfig = {
rebuildConfig: {
onlyModules: [],
},
- makers: [new MakerNsis(), new MakerZip()],
+ makers: [new MakerNsis(), new MakerZip(),
+ {
+ "name": "@electron-forge/maker-deb",
+ "config": {
+ }
+ },
+ {
+ "name": "@electron-forge/maker-rpm",
+ "config": {
+ }
+ }
+ ],
plugins: [
new WebpackPlugin({}),
],
diff --git a/ncti-ide.tar b/ncti-ide.tar
index 9533498a6fa3a86652a9d8c7c41160d9cb62ec69..e33550442040dbc6181e99de094f6727ffabd0ee 100644
Binary files a/ncti-ide.tar and b/ncti-ide.tar differ
diff --git a/package.json b/package.json
index 398554a292ebd446b0e987ea971744bf2e3347eb..58141585c8cf9e45091f76fb6087e323baf96abb 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,10 @@
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
- "electron-rebuild": "node -r ts-node/register ./build/rebuild.ts"
+ "electron-rebuild": "node -r ts-node/register ./build/rebuild.ts",
+ "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
+ "release": "standard-version",
+ "release:minor": "npm run release -- --release-as minor"
},
"repository": {
"type": "git",
@@ -23,36 +26,40 @@
"license": "MIT",
"devDependencies": {
"@electron-forge/cli": "^7.4.0",
- "@electron-forge/maker-squirrel": "^7.4.0",
+ "@electron-forge/maker-deb": "^7.5.0",
+ "@electron-forge/maker-rpm": "^7.5.0",
+ "@electron-forge/maker-squirrel": "^7.5.0",
"@electron-forge/maker-zip": "^7.4.0",
"@electron-forge/plugin-base": "^7.4.0",
"@electron-forge/plugin-webpack": "^7.4.0",
"@electron-forge/shared-types": "^7.4.0",
- "@electron-forge/web-multi-logger": "^7.4.0",
+ "@electron-forge/web-multi-logger": "^7.5.0",
"@types/debug": "^4",
"@types/js-yaml": "^4",
- "@types/node": "^22.0.0",
+ "@types/node": "^22.8.1",
"@types/react": "^18.3.3",
- "@types/react-dom": "^18.3.0",
+ "@types/react-dom": "^18.3.1",
"app-builder-bin": "^4.2.0",
"app-builder-lib": "24.13.3",
"asar": "^3.2.0",
"chalk": "^4.0.0",
+ "conventional-changelog-cli": "^5.0.0",
"copy-webpack-plugin": "^12.0.2",
"cross-env": "^7.0.3",
"css-loader": "6",
- "debug": "^4.3.6",
+ "debug": "^4.3.7",
"electron": "30.1.2",
"extract-zip": "^2.0.1",
"fast-glob": "^3.3.2",
"glob": "^11.0.0",
- "html-webpack-plugin": "^5.6.0",
+ "html-webpack-plugin": "^5.6.2",
"less": "^4.2.0",
"less-loader": "^12.2.0",
- "listr2": "^8.2.4",
+ "listr2": "^8.2.5",
"mini-css-extract-plugin": "^2.9.0",
"node-gyp": "^10.2.0",
"null-loader": "^4.0.1",
+ "standard-version": "^9.5.0",
"style-loader": "^4.0.0",
"style-resources-loader": "^1.5.0",
"ts-loader": "^9.5.1",
@@ -60,8 +67,8 @@
"tsconfig-paths": "^4.2.0",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^5.5.3",
- "undici-types": "^6.19.5",
- "webpack": "^5.93.0",
+ "undici-types": "^6.20.0",
+ "webpack": "^5.94.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4",
"webpack-merge": "^6.0.1",
@@ -69,59 +76,59 @@
"yauzl": "^3.1.3"
},
"dependencies": {
- "@opensumi/ide-addons": "3.3.1-next-1725432779.0",
- "@opensumi/ide-ai-native": "3.3.1-next-1725432779.0",
- "@opensumi/ide-comments": "3.3.1-next-1725432779.0",
- "@opensumi/ide-core-browser": "3.3.1-next-1725432779.0",
- "@opensumi/ide-core-common": "3.3.1-next-1725432779.0",
- "@opensumi/ide-core-electron-main": "3.3.1-next-1725432779.0",
- "@opensumi/ide-core-node": "3.3.1-next-1725432779.0",
- "@opensumi/ide-debug": "3.3.1-next-1725432779.0",
- "@opensumi/ide-decoration": "3.3.1-next-1725432779.0",
- "@opensumi/ide-design": "3.3.1-next-1725432779.0",
- "@opensumi/ide-editor": "3.3.1-next-1725432779.0",
- "@opensumi/ide-electron-basic": "3.3.1-next-1725432779.0",
- "@opensumi/ide-explorer": "3.3.1-next-1725432779.0",
- "@opensumi/ide-extension": "3.3.1-next-1725432779.0",
- "@opensumi/ide-extension-manager": "3.3.1-next-1725432779.0",
- "@opensumi/ide-extension-storage": "3.3.1-next-1725432779.0",
- "@opensumi/ide-file-scheme": "3.3.1-next-1725432779.0",
- "@opensumi/ide-file-search": "3.3.1-next-1725432779.0",
- "@opensumi/ide-file-service": "3.3.1-next-1725432779.0",
- "@opensumi/ide-file-tree-next": "3.3.1-next-1725432779.0",
- "@opensumi/ide-i18n": "3.3.1-next-1725432779.0",
- "@opensumi/ide-keymaps": "3.3.1-next-1725432779.0",
- "@opensumi/ide-logs": "3.3.1-next-1725432779.0",
- "@opensumi/ide-main-layout": "3.3.1-next-1725432779.0",
- "@opensumi/ide-markdown": "3.3.1-next-1725432779.0",
- "@opensumi/ide-markers": "3.3.1-next-1725432779.0",
- "@opensumi/ide-menu-bar": "3.3.1-next-1725432779.0",
- "@opensumi/ide-monaco": "3.3.1-next-1725432779.0",
- "@opensumi/ide-monaco-enhance": "3.3.1-next-1725432779.0",
- "@opensumi/ide-opened-editor": "3.3.1-next-1725432779.0",
- "@opensumi/ide-outline": "3.3.1-next-1725432779.0",
- "@opensumi/ide-output": "3.3.1-next-1725432779.0",
- "@opensumi/ide-overlay": "3.3.1-next-1725432779.0",
- "@opensumi/ide-preferences": "3.3.1-next-1725432779.0",
- "@opensumi/ide-process": "3.3.1-next-1725432779.0",
- "@opensumi/ide-quick-open": "3.3.1-next-1725432779.0",
- "@opensumi/ide-scm": "3.3.1-next-1725432779.0",
- "@opensumi/ide-search": "3.3.1-next-1725432779.0",
- "@opensumi/ide-status-bar": "3.3.1-next-1725432779.0",
- "@opensumi/ide-storage": "3.3.1-next-1725432779.0",
- "@opensumi/ide-task": "3.3.1-next-1725432779.0",
- "@opensumi/ide-terminal-next": "3.3.1-next-1725432779.0",
- "@opensumi/ide-testing": "3.3.1-next-1725432779.0",
- "@opensumi/ide-theme": "3.3.1-next-1725432779.0",
- "@opensumi/ide-toolbar": "3.3.1-next-1725432779.0",
- "@opensumi/ide-variable": "3.3.1-next-1725432779.0",
- "@opensumi/ide-webview": "3.3.1-next-1725432779.0",
- "@opensumi/ide-workspace": "3.3.1-next-1725432779.0",
- "@opensumi/ide-workspace-edit": "3.3.1-next-1725432779.0",
- "@opensumi/tree-sitter-wasm": "0.0.2",
+ "@opensumi/ide-addons": "3.5.0",
+ "@opensumi/ide-ai-native": "3.5.0",
+ "@opensumi/ide-comments": "3.5.0",
+ "@opensumi/ide-core-browser": "3.5.0",
+ "@opensumi/ide-core-common": "3.5.0",
+ "@opensumi/ide-core-electron-main": "3.5.0",
+ "@opensumi/ide-core-node": "3.5.0",
+ "@opensumi/ide-debug": "3.5.0",
+ "@opensumi/ide-decoration": "3.5.0",
+ "@opensumi/ide-design": "3.5.0",
+ "@opensumi/ide-editor": "3.5.0",
+ "@opensumi/ide-electron-basic": "3.5.0",
+ "@opensumi/ide-explorer": "3.5.0",
+ "@opensumi/ide-extension": "3.5.0",
+ "@opensumi/ide-extension-manager": "3.5.0",
+ "@opensumi/ide-extension-storage": "3.5.0",
+ "@opensumi/ide-file-scheme": "3.5.0",
+ "@opensumi/ide-file-search": "3.5.0",
+ "@opensumi/ide-file-service": "3.5.0",
+ "@opensumi/ide-file-tree-next": "3.5.0",
+ "@opensumi/ide-i18n": "3.5.0",
+ "@opensumi/ide-keymaps": "3.5.0",
+ "@opensumi/ide-logs": "3.5.0",
+ "@opensumi/ide-main-layout": "3.5.0",
+ "@opensumi/ide-markdown": "3.5.0",
+ "@opensumi/ide-markers": "3.5.0",
+ "@opensumi/ide-menu-bar": "3.5.0",
+ "@opensumi/ide-monaco": "3.5.0",
+ "@opensumi/ide-monaco-enhance": "3.5.0",
+ "@opensumi/ide-opened-editor": "3.5.0",
+ "@opensumi/ide-outline": "3.5.0",
+ "@opensumi/ide-output": "3.5.0",
+ "@opensumi/ide-overlay": "3.5.0",
+ "@opensumi/ide-preferences": "3.5.0",
+ "@opensumi/ide-process": "3.5.0",
+ "@opensumi/ide-quick-open": "3.5.0",
+ "@opensumi/ide-scm": "3.5.0",
+ "@opensumi/ide-search": "3.5.0",
+ "@opensumi/ide-status-bar": "3.5.0",
+ "@opensumi/ide-storage": "3.5.0",
+ "@opensumi/ide-task": "3.5.0",
+ "@opensumi/ide-terminal-next": "3.5.0",
+ "@opensumi/ide-testing": "3.5.0",
+ "@opensumi/ide-theme": "3.5.0",
+ "@opensumi/ide-toolbar": "3.5.0",
+ "@opensumi/ide-variable": "3.5.0",
+ "@opensumi/ide-webview": "3.5.0",
+ "@opensumi/ide-workspace": "3.5.0",
+ "@opensumi/ide-workspace-edit": "3.5.0",
+ "@opensumi/tree-sitter-wasm": "1.1.2",
"@vscode/spdlog": "^0.15.0",
"buffer": "^6.0.3",
- "electron-updater": "6.2.1",
+ "electron-updater": "6.3.9",
"js-yaml": "^4.1.0",
"mri": "^1.2.0",
"process": "^0.11.10",
diff --git a/product.json b/product.json
index 2ca443f32d0cd3508b6e9a81641c35e683b6750e..aa1a97b7ca38f039146ec836365d05a3e48aa169 100644
--- a/product.json
+++ b/product.json
@@ -7,4 +7,4 @@
"autoUpdaterConfigUrl": "",
"commit": "",
"date": ""
-}
\ No newline at end of file
+}
diff --git a/src/ai/browser/ai-model.contribution.ts b/src/ai/browser/ai-model.contribution.ts
new file mode 100644
index 0000000000000000000000000000000000000000..15c535ce73bfd74190a221006d25bbc28e0bc2a4
--- /dev/null
+++ b/src/ai/browser/ai-model.contribution.ts
@@ -0,0 +1,249 @@
+import { Autowired } from '@opensumi/di'
+import { AI_NATIVE_SETTING_GROUP_ID, localize, MaybePromise, Delayer, CommandService } from '@opensumi/ide-core-common';
+import { Domain, PreferenceContribution, PreferenceSchema, ClientAppContribution, IClientApp, PreferenceService, COMMON_COMMANDS, IPreferenceSettingsService } from '@opensumi/ide-core-browser'
+import { ISettingRegistry, SettingContribution } from '@opensumi/ide-preferences';
+import { AIModelServicePath, IAIModelServiceProxy, ModelSettingId } from '../common'
+import { OutputChannel } from '@opensumi/ide-output/lib/browser/output.channel';
+import { OutputService } from '@opensumi/ide-output/lib/browser/output.service';
+import { MessageService } from '@opensumi/ide-overlay/lib/browser/message.service';
+
+const ModelSettingIdKeys = Object.keys(ModelSettingId);
+
+const aiNativePreferenceSchema: PreferenceSchema = {
+ properties: {
+ [ModelSettingId.baseUrl]: {
+ type: 'string',
+ defaultValue: 'http://127.0.0.1:11434/v1',
+ },
+ [ModelSettingId.apiKey]: {
+ type: 'string',
+ },
+ [ModelSettingId.chatModelName]: {
+ type: 'string',
+ },
+ [ModelSettingId.chatSystemPrompt]: {
+ type: 'string',
+ },
+ [ModelSettingId.chatMaxTokens]: {
+ type: 'number',
+ minimum: 0,
+ defaultValue: 1024,
+ description: localize('preference.ai.model.maxTokens.description'),
+ },
+ [ModelSettingId.chatTemperature]: {
+ type: 'string',
+ // minimum: 0,
+ // maximum: 1,
+ defaultValue: '0.20',
+ description: localize('preference.ai.model.temperature.description'),
+ },
+ [ModelSettingId.chatPresencePenalty]: {
+ type: 'string',
+ // minimum: -2.0,
+ // maximum: 2.0,
+ defaultValue: '1.0',
+ description: localize('preference.ai.model.presencePenalty.description'),
+ },
+ [ModelSettingId.chatFrequencyPenalty]: {
+ type: 'string',
+ // minimum: -2.0,
+ // maximum: 2.0,
+ defaultValue: '1.0',
+ description: localize('preference.ai.model.frequencyPenalty.description'),
+ },
+ [ModelSettingId.chatTopP]: {
+ type: 'string',
+ // minimum: 0,
+ // maximum: 1,
+ defaultValue: '1',
+ description: localize('preference.ai.model.topP.description'),
+ },
+ [ModelSettingId.codeModelName]: {
+ type: 'string',
+ description: localize('preference.ai.model.code.modelName.tooltip')
+ },
+ [ModelSettingId.codeSystemPrompt]: {
+ type: 'string',
+ },
+ [ModelSettingId.codeMaxTokens]: {
+ type: 'number',
+ minimum: 0,
+ defaultValue: 64,
+ description: localize('preference.ai.model.maxTokens.description'),
+ },
+ [ModelSettingId.codeTemperature]: {
+ type: 'string',
+ defaultValue: '0.20',
+ description: localize('preference.ai.model.temperature.description'),
+ },
+ [ModelSettingId.codePresencePenalty]: {
+ type: 'string',
+ // minimum: -2.0,
+ // maximum: 2.0,
+ defaultValue: '1',
+ description: localize('preference.ai.model.presencePenalty.description'),
+ },
+ [ModelSettingId.codeFrequencyPenalty]: {
+ type: 'string',
+ // minimum: -2.0,
+ // maximum: 2.0,
+ defaultValue: '1',
+ description: localize('preference.ai.model.frequencyPenalty.description'),
+ },
+ [ModelSettingId.codeTopP]: {
+ type: 'string',
+ // minimum: 0,
+ // maximum: 1,
+ defaultValue: '1',
+ description: localize('preference.ai.model.topP.description'),
+ },
+ [ModelSettingId.codeFimTemplate]: {
+ type: 'string',
+ description: localize('preference.ai.model.code.fimTemplate.tooltip'),
+ },
+ },
+};
+
+@Domain(ClientAppContribution, PreferenceContribution, SettingContribution)
+export class AIModelContribution implements PreferenceContribution, SettingContribution, ClientAppContribution {
+ schema = aiNativePreferenceSchema;
+
+ @Autowired(PreferenceService)
+ private readonly preferenceService: PreferenceService;
+
+ @Autowired(AIModelServicePath)
+ modelService: IAIModelServiceProxy
+
+ @Autowired(MessageService)
+ messageService: MessageService;
+
+ @Autowired(OutputService)
+ outputService: OutputService;
+
+ @Autowired(CommandService)
+ commandService: CommandService
+
+ @Autowired(IPreferenceSettingsService)
+ preferenceSettingsService: IPreferenceSettingsService
+
+ #output: OutputChannel
+
+ get output() {
+ if (!this.#output) {
+ this.#output = this.outputService.getChannel('AI Native')
+ }
+ return this.#output
+ }
+
+ onDidStart(app: IClientApp): MaybePromise {
+ const delayer = new Delayer(100);
+ const values: Record = {}
+ ModelSettingIdKeys.forEach((idKey) => {
+ values[idKey] = this.preferenceService.getValid(ModelSettingId[idKey])
+ this.preferenceService.onSpecificPreferenceChange(ModelSettingId[idKey], (change) => {
+ values[idKey] = change.newValue
+ delayer.trigger(() => this.setModeConfig(values))
+ })
+ })
+ this.checkModelConfig(values).then((valid) => {
+ if (valid) {
+ delayer.trigger(() => this.setModeConfig(values))
+ }
+ })
+ }
+
+ registerSetting(registry: ISettingRegistry): void {
+ registry.registerSettingSection(AI_NATIVE_SETTING_GROUP_ID, {
+ title: localize('preference.ai.model.title'),
+ preferences: [
+ {
+ id: ModelSettingId.baseUrl,
+ localized: 'preference.ai.model.baseUrl',
+ },
+ {
+ id: ModelSettingId.apiKey,
+ localized: 'preference.ai.model.apiKey',
+ },
+ {
+ id: ModelSettingId.chatModelName,
+ localized: 'preference.ai.model.chat.modelName',
+ },
+ {
+ id: ModelSettingId.chatSystemPrompt,
+ localized: 'preference.ai.model.chat.systemPrompt',
+ },
+ {
+ id: ModelSettingId.chatMaxTokens,
+ localized: 'preference.ai.model.chat.maxTokens',
+ },
+ {
+ id: ModelSettingId.chatTemperature,
+ localized: 'preference.ai.model.chat.temperature',
+ },
+ {
+ id: ModelSettingId.chatPresencePenalty,
+ localized: 'preference.ai.model.chat.presencePenalty',
+ },
+ {
+ id: ModelSettingId.chatFrequencyPenalty,
+ localized: 'preference.ai.model.chat.frequencyPenalty',
+ },
+ {
+ id: ModelSettingId.chatTopP,
+ localized: 'preference.ai.model.chat.topP',
+ },
+ {
+ id: ModelSettingId.codeModelName,
+ localized: 'preference.ai.model.code.modelName',
+ },
+ {
+ id: ModelSettingId.codeSystemPrompt,
+ localized: 'preference.ai.model.code.systemPrompt',
+ },
+ {
+ id: ModelSettingId.codeMaxTokens,
+ localized: 'preference.ai.model.code.maxTokens',
+ },
+ {
+ id: ModelSettingId.codeTemperature,
+ localized: 'preference.ai.model.code.temperature',
+ },
+ {
+ id: ModelSettingId.codePresencePenalty,
+ localized: 'preference.ai.model.code.presencePenalty',
+ },
+ {
+ id: ModelSettingId.codeFrequencyPenalty,
+ localized: 'preference.ai.model.code.frequencyPenalty',
+ },
+ {
+ id: ModelSettingId.codeTopP,
+ localized: 'preference.ai.model.code.topP',
+ },
+ {
+ id: ModelSettingId.codeFimTemplate,
+ localized: 'preference.ai.model.code.fimTemplate',
+ },
+ ],
+ });
+ }
+
+ private async checkModelConfig(values: Record) {
+ if (values.baseUrl && values.chatModelName) {
+ return true
+ }
+ const res = await this.messageService.info(localize('ai.model.noConfig'), [
+ localize('ai.model.go')
+ ])
+ if (res === localize('ai.model.go')) {
+ await this.commandService.executeCommand(COMMON_COMMANDS.OPEN_PREFERENCES.id)
+ this.preferenceSettingsService.scrollToPreference(ModelSettingId.baseUrl)
+ }
+ return false
+ }
+
+ private setModeConfig(values: Record) {
+ this.modelService.setConfig(values)
+ this.output.appendLine(`model config: ${JSON.stringify(values, null, 2)}`)
+ }
+}
diff --git a/src/ai/browser/ai-native.contribution.ts b/src/ai/browser/ai-native.contribution.ts
index a6a2f909e165214e5e69c81dd1cc2f97b5981ea6..379e78b29d99bd6282d31fde3fcb740804efe15e 100644
--- a/src/ai/browser/ai-native.contribution.ts
+++ b/src/ai/browser/ai-native.contribution.ts
@@ -6,10 +6,12 @@ import {
IChatContent,
IChatProgress,
IAIBackService,
+ CancellationToken,
+ ChatResponse,
} from '@opensumi/ide-core-common';
import { ClientAppContribution, Domain, getIcon } from '@opensumi/ide-core-browser';
import { ComponentContribution, ComponentRegistry } from '@opensumi/ide-core-browser/lib/layout';
-import { AINativeCoreContribution, ERunStrategy, IChatFeatureRegistry, IInlineChatFeatureRegistry, IRenameCandidatesProviderRegistry, ITerminalProviderRegistry, TChatSlashCommandSend, TerminalSuggestionReadableStream } from '@opensumi/ide-ai-native/lib/browser/types';
+import { AINativeCoreContribution, ERunStrategy, IChatFeatureRegistry, IInlineChatFeatureRegistry, IProblemFixContext, IProblemFixProviderRegistry, IRenameCandidatesProviderRegistry, ITerminalProviderRegistry, TChatSlashCommandSend, TerminalSuggestionReadableStream } from '@opensumi/ide-ai-native/lib/browser/types';
import { ICodeEditor, MarkdownString, NewSymbolNameTag } from '@opensumi/ide-monaco';
import { MessageService } from '@opensumi/ide-overlay/lib/browser/message.service';
import { BaseTerminalDetectionLineMatcher, JavaMatcher, MatcherType, NodeMatcher, NPMMatcher, ShellMatcher, TSCMatcher } from '@opensumi/ide-ai-native/lib/browser/contrib/terminal/matcher';
@@ -518,4 +520,35 @@ export class AINativeContribution implements ComponentContribution, AINativeCore
return stream;
});
}
+
+
+ registerProblemFixFeature(registry: IProblemFixProviderRegistry): void {
+ registry.registerHoverFixProvider({
+ provideFix: async (
+ editor: ICodeEditor,
+ context: IProblemFixContext,
+ token: CancellationToken,
+ ): Promise => {
+ const { marker, editRange } = context;
+
+ const prompt = `原始代码内容:
+\`\`\`
+${editor.getModel()!.getValueInRange(editRange)}
+\`\`\`
+
+ lint error 信息:
+
+ ${marker.message}.
+
+ 请根据 lint error 信息修复代码!
+ 不需要任何解释,只要返回修复后的代码块内容`;
+
+ const controller = new InlineChatController({ enableCodeblockRender: true });
+ const stream = await this.aiBackService.requestStream(prompt, {}, token);
+ controller.mountReadable(stream);
+
+ return controller;
+ },
+ });
+ }
}
diff --git a/src/ai/browser/command/command.service.ts b/src/ai/browser/command/command.service.ts
index 597a72cdac51ce27d9a8f749906b4207bdb157c1..081f92f4d9f26dc8717d912ac99e5b9db4a167b0 100644
--- a/src/ai/browser/command/command.service.ts
+++ b/src/ai/browser/command/command.service.ts
@@ -703,7 +703,6 @@ export class AICommandService {
async requestForClassifyCommand(commands: Command[]) {
const prompt = this.promptManager.groupCommand(commands.map((c) => c.id).join(','));
const groupReply = await this.requestToModel(prompt);
- console.log(111, prompt, groupReply)
const groupReg = new RegExp(
`\\[(?${Object.keys(this.commandGroups).join('|')})\\]:\\s?(?.*)`,
diff --git a/src/ai/browser/index.ts b/src/ai/browser/index.ts
index 265dcbf8eb635439ac0351d51ed77fb4d8d91ed2..13a9fa6a1b93b6aef233731c9a96c5bc7864e7a4 100644
--- a/src/ai/browser/index.ts
+++ b/src/ai/browser/index.ts
@@ -6,8 +6,8 @@ import { AIRunContribution } from './ai-run.contribution'
import { AICommandPromptManager } from './command/command-prompt-manager'
import { AICommandService } from './command/command.service'
import { InlineChatOperationModel } from './inline-chat-operation'
-import { AILocalModelContribution } from './ai-local-model.contribution'
-import { AILocalModelServicePath } from '../common'
+import { AIModelContribution } from './ai-model.contribution'
+import { AIModelServicePath } from '../common'
export * from './constants'
@@ -19,12 +19,12 @@ export class AIFeatureModule extends BrowserModule {
AICommandPromptManager,
AICommandService,
InlineChatOperationModel,
- AILocalModelContribution,
+ AIModelContribution,
];
backServices = [
{
- servicePath: AILocalModelServicePath,
+ servicePath: AIModelServicePath,
}
]
}
diff --git a/src/ai/common/types.ts b/src/ai/common/types.ts
index 58a0870f53221792d4f29e7670ee5705461062f9..971be7e87a660e68b299c5b39090a6883d9f18e5 100644
--- a/src/ai/common/types.ts
+++ b/src/ai/common/types.ts
@@ -1,27 +1,29 @@
-export const AILocalModelServicePath = 'AILocalModelServicePath';
+export const AIModelServicePath = 'AIModelServicePath';
-export const IAILocalModelServiceProxy = Symbol('IAILocalModelServiceProxy')
+export const IAIModelServiceProxy = Symbol('IAIModelServiceProxy')
-export interface IAILocalModelServiceProxy {
+export interface IAIModelServiceProxy {
setConfig(values: Record): Promise
}
-export const LocalModelSettingId = {
- completeUrl: 'ai.native.local_model.complete_url',
- apiKey: 'ai.native.local_model.api_key',
- chatModelName: 'ai.native.local_model.chat.model_name',
- chatSystemPrompt: 'ai.native.local_model.chat.system_prompt',
- chatTemperature: 'ai.native.local_model.chat.temperature',
- chatMaxTokens: 'ai.native.local_model.chat.max_tokens',
- chatPresencePenalty: 'ai.native.local_model.chat.presence_penalty',
- chatTopP: 'ai.native.local_model.chat.top_p',
- codeCompletionModelName: 'ai.native.local_model.code_completion.model_name',
- codeCompletionSystemPrompt: 'ai.native.local_model.code_completion.system_prompt',
- codeCompletionUserPrompt: 'ai.native.local_model.code_completion.user_prompt',
- codeCompletionTemperature: 'ai.native.local_model.code_completion.temperature',
- codeCompletionMaxTokens: 'ai.native.local_model.code_completion.max_tokens',
- codeCompletionPresencePenalty: 'ai.native.local_model.code_completion.presence_penalty',
- codeCompletionTopP: 'ai.native.local_model.code_completion.top_p',
+export const ModelSettingId = {
+ baseUrl: 'ai.model.baseUrl',
+ apiKey: 'ai.model.apiKey',
+ chatModelName: 'ai.model.chat.modelName',
+ chatSystemPrompt: 'ai.model.chat.systemPrompt',
+ chatTemperature: 'ai.model.chat.temperature',
+ chatMaxTokens: 'ai.model.chat.maxTokens',
+ chatPresencePenalty: 'ai.model.chat.presencePenalty',
+ chatFrequencyPenalty: 'ai.model.chat.frequencyPenalty',
+ chatTopP: 'ai.model.chat.topP',
+ codeModelName: 'ai.model.code.modelName',
+ codeSystemPrompt: 'ai.model.code.systemPrompt',
+ codeFimTemplate: 'ai.model.code.fimTemplate',
+ codeTemperature: 'ai.model.code.temperature',
+ codeMaxTokens: 'ai.model.code.maxTokens',
+ codePresencePenalty: 'ai.model.code.presencePenalty',
+ codeFrequencyPenalty: 'ai.model.code.frequencyPenalty',
+ codeTopP: 'ai.model.code.topP',
}
-export type ILocalModelConfig = Record;
+export type IModelConfig = Record;
diff --git a/src/ai/node/ai-back.service.ts b/src/ai/node/ai-back.service.ts
index c09cce1e1701193559166c1216a5b03a154a22e3..afc6eb74a7a0e41f432d41381f48089a8befdba7 100644
--- a/src/ai/node/ai-back.service.ts
+++ b/src/ai/node/ai-back.service.ts
@@ -9,8 +9,8 @@ import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream';
import type { Response, fetch as FetchType } from 'undici-types';
import { ILogServiceManager } from '@opensumi/ide-logs';
-import { ChatCompletionChunk, ChatCompletion } from './types';
-import { AILocalModelService } from './local-model.service'
+import { ChatCompletionChunk, ChatCompletion, Completion } from './types';
+import { AIModelService } from './model.service'
@Injectable()
export class AIBackService extends BaseAIBackService implements IAIBackService {
@@ -19,8 +19,8 @@ export class AIBackService extends BaseAIBackService implements IAIBackService {
@Autowired(ILogServiceManager)
private readonly loggerManager: ILogServiceManager;
- @Autowired(AILocalModelService)
- localModelService: AILocalModelService
+ @Autowired(AIModelService)
+ modelService: AIModelService
private historyMessages: {
role: ChatCompletionRequestMessageRoleEnum;
@@ -33,64 +33,99 @@ export class AIBackService extends BaseAIBackService implements IAIBackService {
}
override async request(input: string, options: IAIBackServiceOption, cancelToken?: CancellationToken): Promise {
- // this.historyMessages.push({ role: ChatCompletionRequestMessageRoleEnum.User, content: input })
- // if (this.historyMessages.length > 50) {
- // this.historyMessages = this.historyMessages.slice(-50)
- // }
- const message = [{ role: ChatCompletionRequestMessageRoleEnum.User, content: input }]
-
- const response = await this.fetchModel(message, {
- isCodeCompletion: false,
- stream: false,
- }, cancelToken);
-
- if (!response) {
- this.logger.log('ai request failed, ai local model config error');
+ const config = this.checkConfig()
+ if (!config) {
return {
errorCode: 1,
- errorMsg: 'ai local model config error',
+ errorMsg: 'miss config',
data: ''
}
}
- const data = await response.json() as ChatCompletion
- const content = data?.choices?.[0]?.message?.content;
+ const messages = [
+ ...(config.chatSystemPrompt ? [
+ {
+ role: ChatCompletionRequestMessageRoleEnum.System,
+ content: config.chatSystemPrompt,
+ },
+ ] : []),
+ { role: ChatCompletionRequestMessageRoleEnum.User, content: input }
+ ]
- if (content) {
- this.historyMessages.push({ role: ChatCompletionRequestMessageRoleEnum.Assistant, content });
+ const response = await this.fetchModel(
+ this.getCompletionUrl(config.baseUrl),
+ {
+ model: config.chatModelName,
+ messages,
+ stream: false,
+ max_tokens: config.chatMaxTokens,
+ temperature: config.chatTemperature,
+ presence_penalty: config.chatPresencePenalty,
+ frequency_penalty: config.codeFrequencyPenalty,
+ top_p: config.chatTopP,
+ },
+ cancelToken
+ );
+
+ if (!response.ok) {
+ this.logger.error(`ai request failed: status: ${response.status}, body: ${await response.text()}`);
+ return {
+ errorCode: 1,
+ errorMsg: `request failed: ${response.status}`,
+ }
}
- return {
- errorCode: 0,
- data: content,
+ try {
+ const data = await response.json() as ChatCompletion
+ const content = data?.choices?.[0]?.message?.content;
+
+ return {
+ errorCode: 0,
+ data: content,
+ }
+ } catch (err: any) {
+ this.logger.error(`ai request body parse error: ${err?.message}`);
+ throw err
}
}
override async requestStream(input: string, options: IAIBackServiceOption, cancelToken?: CancellationToken) {
- // this.historyMessages.push({ role: ChatCompletionRequestMessageRoleEnum.User, content: input })
- // if (this.historyMessages.length > 50) {
- // this.historyMessages = this.historyMessages.slice(-50)
- // }
- const { chatSystemPrompt } = this.localModelService.config || {}
- const message = [
- ...(chatSystemPrompt ? [
+ const readableSteam = new SumiReadableStream()
+
+ const config = this.checkConfig()
+ if (!config) {
+ readableSteam.emitError(new Error('miss config'));
+ readableSteam.end();
+ return readableSteam
+ }
+ const messages = [
+ ...(config.chatSystemPrompt ? [
{
role: ChatCompletionRequestMessageRoleEnum.System,
- content: chatSystemPrompt,
+ content: config.chatSystemPrompt,
},
] : []),
{ role: ChatCompletionRequestMessageRoleEnum.User, content: input }
]
+
+ const response = await this.fetchModel(
+ this.getCompletionUrl(config.baseUrl),
+ {
+ model: config.chatModelName,
+ messages,
+ stream: true,
+ max_tokens: config.chatMaxTokens,
+ temperature: config.chatTemperature,
+ presence_penalty: config.chatPresencePenalty,
+ frequency_penalty: config.codeFrequencyPenalty,
+ top_p: config.chatTopP,
+ },
+ cancelToken,
+ )
- const response = await this.fetchModel(message, {
- isCodeCompletion: false,
- stream: true,
- }, cancelToken);
-
- const readableSteam = new SumiReadableStream()
-
- if (!response) {
- readableSteam.emitError(new Error('ai local model config error'));
+ if (!response.ok) {
+ this.logger.error(`ai request stream failed: status: ${response.status}, body: ${await response.text()}`);
+ readableSteam.emitError(new Error('Readable Stream Abort'));
readableSteam.end();
return readableSteam
}
@@ -102,12 +137,6 @@ export class AIBackService extends BaseAIBackService implements IAIBackService {
return readableSteam
}
- if (!response.ok) {
- this.logger.error(`ai request stream failed: status: ${response.status}, body: ${await response.text()}`);
- readableSteam.emitError(new Error('Readable Stream Abort'));
- readableSteam.end();
- return readableSteam
- }
const { logger } = this;
@@ -157,104 +186,120 @@ export class AIBackService extends BaseAIBackService implements IAIBackService {
}
async requestCompletion(input: IAICompletionOption, cancelToken?: CancellationToken) {
- const { codeCompletionSystemPrompt, codeCompletionUserPrompt } = this.localModelService.config || {}
- if (!codeCompletionUserPrompt) {
- this.logger.warn('miss config.codeCompletionUserPrompt')
+ const config = this.checkConfig(true)
+ if (!config) {
return {
sessionId: input.sessionId,
codeModelList: [],
}
}
- const userContent = codeCompletionUserPrompt.replace('{prefix}', input.prompt).replace('{suffix}', input.suffix || '')
- const messages = [
- ...(codeCompletionSystemPrompt ? [
- {
- role: ChatCompletionRequestMessageRoleEnum.System,
- content: codeCompletionSystemPrompt,
- },
- ] : []),
+
+ const response = await this.fetchModel(
+ this.getCompletionUrl(config.baseUrl, !config.codeFimTemplate),
{
- role: ChatCompletionRequestMessageRoleEnum.User,
- content: userContent,
- }
- ]
- const response = await this.fetchModel(messages, {
- isCodeCompletion: true,
- stream: false,
- }, cancelToken);
+ stream: false,
+ model: config.codeModelName || config.chatModelName,
+ max_tokens: config.codeMaxTokens,
+ temperature: config.codeTemperature,
+ presence_penalty: config.codePresencePenalty,
+ frequency_penalty: config.codeFrequencyPenalty,
+ top_p: config.codeTopP,
+ ...(config.codeFimTemplate ? {
+ messages: [
+ ...(config.codeSystemPrompt ? [
+ {
+ role: ChatCompletionRequestMessageRoleEnum.System,
+ content: config.codeSystemPrompt,
+ },
+ ] : []),
+ {
+ role: ChatCompletionRequestMessageRoleEnum.User,
+ content: config.codeFimTemplate.replace('{prefix}', input.prompt).replace('{suffix}', input.suffix || ''),
+ }
+ ]
+ } : {
+ prompt: input.prompt,
+ suffix: input.suffix,
+ })
+ },
+ cancelToken
+ );
- if (!response) {
+ if (!response.ok) {
+ this.logger.error(`ai request completion failed: status: ${response.status}, body: ${await response.text()}`);
return {
sessionId: input.sessionId,
codeModelList: [],
}
}
- const data = await response.json() as ChatCompletion
- const content = data?.choices?.[0]?.message?.content;
- if (!content) {
+ try {
+ const data = await response.json() as ChatCompletion | Completion
+ const content = config.codeFimTemplate ? (data as ChatCompletion)?.choices?.[0]?.message?.content : (data as Completion)?.choices?.[0]?.text;
+ if (!content) {
+ return {
+ sessionId: input.sessionId,
+ codeModelList: [],
+ }
+ }
return {
sessionId: input.sessionId,
- codeModelList: [],
+ codeModelList: [{ content }],
}
+ } catch (err: any) {
+ this.logger.error(`ai request completion body parse error: ${err?.message}`);
+ throw err
+ }
+ }
+
+ private checkConfig(isCodeCompletion = false) {
+ const { config } = this.modelService
+ if (!config) {
+ this.logger.warn('miss config')
+ return null
+ }
+ if (!config.baseUrl) {
+ this.logger.warn('miss config baseUrl')
+ return null
}
- return {
- sessionId: input.sessionId,
- codeModelList: [{ content }],
+ const modelName = isCodeCompletion ? (config.codeModelName || config.chatModelName) : config.chatModelName
+ if (!modelName) {
+ this.logger.warn('miss config modelName')
+ return null
}
+ return config
}
- private async fetchModel(messages: ChatCompletionRequestMessage[], { isCodeCompletion = false, stream = false }, cancelToken?: CancellationToken): Promise {
+ private async fetchModel(url: string | URL, body: Record, cancelToken?: CancellationToken): Promise {
const controller = new AbortController();
const signal = controller.signal;
- const { config } = this.localModelService
- if (!config || !config.completeUrl || !config.chatModelName) {
- if (!config) {
- this.logger.warn('miss config')
- return null
- }
- if (!config.completeUrl) {
- this.logger.warn('miss config.completeUrl')
- return null
- }
- if (!config.chatModelName) {
- this.logger.warn('miss config.modelName')
- return null
- }
- }
+
+ const { config } = this.modelService
cancelToken?.onCancellationRequested(() => {
controller.abort();
});
return (fetch as typeof FetchType)(
- config.completeUrl,
+ url,
{
signal,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
- ...(config.apiKey ? {
+ ...(config?.apiKey ? {
Authorization: `Bearer ${config.apiKey}`
} : null),
},
- body: JSON.stringify({
- model: isCodeCompletion ? (config.codeCompletionModelName || config.chatModelName) : config.chatModelName,
- messages: messages,
- stream,
- ...(isCodeCompletion ? {
- max_tokens: config.codeCompletionMaxTokens,
- temperature: config.codeCompletionTemperature,
- presence_penalty: config.codeCompletionPresencePenalty,
- top_p: config.codeCompletionTopP,
- } : {
- max_tokens: config.chatMaxTokens,
- temperature: config.chatTemperature,
- presence_penalty: config.chatPresencePenalty,
- top_p: config.chatTopP,
- })
- }),
+ body: JSON.stringify(body),
},
);
}
+
+ private getCompletionUrl(baseUrl: string, supportFim = false) {
+ if (!baseUrl.endsWith('/')) {
+ baseUrl += '/'
+ }
+ return new URL(supportFim ? 'completions' : 'chat/completions', baseUrl);
+ }
}
diff --git a/src/ai/node/index.ts b/src/ai/node/index.ts
index c3da0e3ac0a15ae779aa9b0a625401961bc15d43..bd37638596b0c12b6e7977af6f46e7666966a21f 100644
--- a/src/ai/node/index.ts
+++ b/src/ai/node/index.ts
@@ -5,8 +5,8 @@ import { IShellIntegrationService } from '@opensumi/ide-terminal-next/lib/node/s
import { ShellIntegrationService } from './shell-integration'
import { AIBackService } from './ai-back.service'
-import { AILocalModelServiceProxy, AILocalModelService } from './local-model.service'
-import { AILocalModelServicePath, IAILocalModelServiceProxy } from '../common'
+import { AIModelServiceProxy, AIModelService } from './model.service'
+import { AIModelServicePath, IAIModelServiceProxy } from '../common'
@Injectable()
export class AIServiceModule extends NodeModule {
@@ -22,19 +22,19 @@ export class AIServiceModule extends NodeModule {
override: true,
},
{
- token: AILocalModelService,
- useClass: AILocalModelService,
+ token: AIModelService,
+ useClass: AIModelService,
},
{
- token: IAILocalModelServiceProxy,
- useClass: AILocalModelServiceProxy,
+ token: IAIModelServiceProxy,
+ useClass: AIModelServiceProxy,
}
]
backServices = [
{
- servicePath: AILocalModelServicePath,
- token: IAILocalModelServiceProxy,
+ servicePath: AIModelServicePath,
+ token: IAIModelServiceProxy,
}
]
}
diff --git a/src/ai/node/model.service.ts b/src/ai/node/model.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e63b732468ec71f91f0abe5197f4b444afe4b115
--- /dev/null
+++ b/src/ai/node/model.service.ts
@@ -0,0 +1,56 @@
+import { Injectable, Autowired } from '@opensumi/di';
+import { INodeLogger } from '@opensumi/ide-core-node'
+import { IAIModelServiceProxy, IModelConfig } from '../common'
+import { ILogServiceManager } from '@opensumi/ide-logs';
+
+@Injectable()
+export class AIModelService {
+ private logger: INodeLogger
+
+ @Autowired(ILogServiceManager)
+ private readonly loggerManager: ILogServiceManager;
+
+ #config: IModelConfig | undefined
+
+ constructor() {
+ this.logger = this.loggerManager.getLogger('ai' as any);
+ }
+
+ get config(): IModelConfig | undefined {
+ const config = this.#config
+ if (!config) return
+ return {
+ ...config,
+ chatTemperature: this.coerceNumber(config.chatTemperature, 0, 1, 0.2),
+ chatPresencePenalty: this.coerceNumber(config.chatPresencePenalty, -2, 2, 1),
+ chatFrequencyPenalty: this.coerceNumber(config.chatFrequencyPenalty, -2, 2, 1),
+ chatTopP: this.coerceNumber(config.chatTopP, 0, 1, 0.95),
+ codeTemperature: this.coerceNumber(config.codeTemperature, 0, 1, 0.2),
+ codePresencePenalty: this.coerceNumber(config.codePresencePenalty, -2, 2, 1),
+ codeFrequencyPenalty: this.coerceNumber(config.codeFrequencyPenalty, -2, 2, 1),
+ codeTopP: this.coerceNumber(config.codeTopP, 0, 1, 0.95),
+ }
+ }
+
+ async setConfig(config: IModelConfig): Promise {
+ this.#config = config;
+ this.logger.log('[model config]', JSON.stringify(config));
+ }
+
+ private coerceNumber(value: string | number, min: number, max: number, defaultValue: number) {
+ const num = Number(value)
+ if (isNaN(num)) return defaultValue
+ if (num < min || num > max) return defaultValue
+ return num
+ }
+}
+
+@Injectable()
+export class AIModelServiceProxy implements IAIModelServiceProxy {
+ @Autowired(AIModelService)
+ private readonly modelService: AIModelService;
+
+ async setConfig(config: IModelConfig): Promise {
+ this.modelService.setConfig(config)
+ }
+}
diff --git a/src/ai/node/types.ts b/src/ai/node/types.ts
index cad70d40063e17f18dfbc41edaebf7054fea1b6a..7fbb912f90c10a60627ec429b5a5bf760ec18427 100644
--- a/src/ai/node/types.ts
+++ b/src/ai/node/types.ts
@@ -49,3 +49,19 @@ export interface ChatCompletionChunk {
system_fingerprint: string;
choices: ChunkChoice[];
}
+
+export interface CompletionChoice {
+ finish_reason: string;
+ index: number;
+ text: string;
+}
+
+export interface Completion {
+ id: string;
+ choices: Array;
+ created: number;
+ model: string;
+ object: 'text_completion';
+ system_fingerprint?: string;
+ usage?: Usage;
+}
diff --git a/src/auto-updater/electron-main/auto-updater.service.ts b/src/auto-updater/electron-main/auto-updater.service.ts
index 26b765895be8dee970fad2e9d52b6e0d84d52c91..8306d67a811fdbdd69cbcb80859f5e1f0e67e502 100644
--- a/src/auto-updater/electron-main/auto-updater.service.ts
+++ b/src/auto-updater/electron-main/auto-updater.service.ts
@@ -128,6 +128,7 @@ export class AutoUpdaterService {
init() {
if (this.#initialized) return
+ this.#initialized = true
autoUpdater.autoDownload = false
autoUpdater.disableDifferentialDownload = true
autoUpdater.logger = this.logger;
diff --git a/src/auto-updater/update-window/UpdateView.tsx b/src/auto-updater/update-window/UpdateView.tsx
index 8758930a424fcf38086dc3a3f73994778587591c..c64d72f6f713fe188be40bddfe727304f907e851 100644
--- a/src/auto-updater/update-window/UpdateView.tsx
+++ b/src/auto-updater/update-window/UpdateView.tsx
@@ -6,9 +6,9 @@ import styles from './style.module.less'
import { IPC_CHANNEL, ProgressInfo, InitialState, UpdateInfo, UpdateState, EventData } from '../common'
export const UpdateView = () => {
- const [updateInfo, setUpdateInfo] = useState()
- const [progressInfo, setProgressInfo] = useState(null)
- const [updateState, setUpdateState] = useState(null)
+ const [ updateInfo, setUpdateInfo ] = useState()
+ const [ progressInfo, setProgressInfo ] = useState(null)
+ const [ updateState, setUpdateState ] = useState(null)
const releaseHtml = useMemo(() => {
const releaseNotes = updateInfo?.releaseNotes
if (!releaseNotes) return ''
diff --git a/src/auto-updater/update-window/index.html b/src/auto-updater/update-window/index.html
index eee1d20044ecac8eb1551ca62dc1bee296cb8056..068e9bad8a480b706721fce73adae31ead041c0c 100644
--- a/src/auto-updater/update-window/index.html
+++ b/src/auto-updater/update-window/index.html
@@ -24,4 +24,4 @@