diff --git a/HOW_TO_CONTRIBUTE.md b/HOW_TO_CONTRIBUTE.md index 15323527..a9ce1ab5 100644 --- a/HOW_TO_CONTRIBUTE.md +++ b/HOW_TO_CONTRIBUTE.md @@ -4,15 +4,15 @@ This is the official guide on how to contribute to Void. We want to make it as e There are a few ways to contribute: -- ðŸ’Ŧ Complete items on the [Roadmap](https://github.com/orgs/voideditor/projects/2). +- ðŸ’Ŧ Complete items on the [Roadmap](https://github.com/orgs/voideditor-test/projects/2). - ðŸ’Ą Make suggestions in our [Discord](https://discord.gg/RSNjgaugJs). -- ðŸŠī Start new Issues - see [Issues](https://github.com/voideditor/void/issues). +- ðŸŠī Start new Issues - see [Issues](https://github.com/voideditor-test/void/issues). ### Codebase Guide -We [highly recommend reading this](https://github.com/voideditor/void/blob/main/VOID_CODEBASE_GUIDE.md) guide that we put together on Void's sourcecode if you'd like to contribute! +We [highly recommend reading this](https://github.com/voideditor-test/void/blob/main/VOID_CODEBASE_GUIDE.md) guide that we put together on Void's sourcecode if you'd like to contribute! The repo is not as intimidating as it first seems if you read the guide! @@ -87,7 +87,7 @@ Alternatively, if you want to build Void from the terminal, instead of pressing - Make sure you have Node version `20.18.2` (the version in `.nvmrc`)! - If you get `"TypeError: Failed to fetch dynamically imported module"`, make sure all imports end with `.js`. - If you see missing styles, wait a few seconds and then reload. -- If you have any questions, feel free to [submit an issue](https://github.com/voideditor/void/issues/new). You can also refer to VSCode's complete [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute) page. +- If you have any questions, feel free to [submit an issue](https://github.com/voideditor-test/void/issues/new). You can also refer to VSCode's complete [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute) page. - If you get errors like `npm error libtool: error: unrecognised option: '-static'`, make sure you have GNU libtool instead of BSD libtool (BSD is the default in macos) @@ -119,7 +119,7 @@ workspace/ ``` ### Distributing -Void's maintainers distribute Void on our website and in releases. Our build pipeline is a fork of VSCodium, and it works by running GitHub Actions which create the downloadables. The build repo with more instructions lives [here](https://github.com/voideditor/void-builder). +Void's maintainers distribute Void on our website and in releases. Our build pipeline is a fork of VSCodium, and it works by running GitHub Actions which create the downloadables. The build repo with more instructions lives [here](https://github.com/voideditor-test/void-builder). ## Pull Request Guidelines diff --git a/README.md b/README.md index a4467387..eeae9f69 100644 --- a/README.md +++ b/README.md @@ -11,30 +11,30 @@ Void is the open-source Cursor alternative. -This repo contains the full sourcecode for Void. We are currently in [open beta](https://voideditor.com/email) for Discord members (see the `announcements` channel), with a waitlist for our official release. If you're new, welcome! +This repo contains the full sourcecode for Void. We are currently in [open beta](https://voideditor-test.com/email) for Discord members (see the `announcements` channel), with a waitlist for our official release. If you're new, welcome! - 👋 [Discord](https://discord.gg/RSNjgaugJs) -- ðŸ”Ļ [Contribute](https://github.com/voideditor/void/blob/main/HOW_TO_CONTRIBUTE.md) +- ðŸ”Ļ [Contribute](https://github.com/voideditor-test/void/blob/main/HOW_TO_CONTRIBUTE.md) -- 🚙 [Roadmap](https://github.com/orgs/voideditor/projects/2) +- 🚙 [Roadmap](https://github.com/orgs/voideditor-test/projects/2) -- 📝 [Changelog](https://voideditor.com/changelog) +- 📝 [Changelog](https://voideditor-test.com/changelog) -- 🧭 [Codebase Guide](https://github.com/voideditor/void/blob/main/VOID_CODEBASE_GUIDE.md) +- 🧭 [Codebase Guide](https://github.com/voideditor-test/void/blob/main/VOID_CODEBASE_GUIDE.md) ## Contributing 1. Feel free to attend a weekly meeting in our Discord channel if you'd like to contribute! -2. To get started working on Void, see [`HOW_TO_CONTRIBUTE`](https://github.com/voideditor/void/blob/main/HOW_TO_CONTRIBUTE.md). +2. To get started working on Void, see [`HOW_TO_CONTRIBUTE`](https://github.com/voideditor-test/void/blob/main/HOW_TO_CONTRIBUTE.md). 3. We're open to collaborations and suggestions of all types - just reach out. ## Reference -Void is a fork of the [vscode](https://github.com/microsoft/vscode) repository. For a guide to the VSCode/Void codebase, see [`VOID_CODEBASE_GUIDE`](https://github.com/voideditor/void/blob/main/VOID_CODEBASE_GUIDE.md). +Void is a fork of the [vscode](https://github.com/microsoft/vscode) repository. For a guide to the VSCode/Void codebase, see [`VOID_CODEBASE_GUIDE`](https://github.com/voideditor-test/void/blob/main/VOID_CODEBASE_GUIDE.md). ## Support -Feel free to reach out in our Discord or contact us via email: hello@voideditor.com. +Feel free to reach out in our Discord or contact us via email: hello@voideditor-test.com. diff --git a/VOID_CODEBASE_GUIDE.md b/VOID_CODEBASE_GUIDE.md index 5c70cef6..e50087cf 100644 --- a/VOID_CODEBASE_GUIDE.md +++ b/VOID_CODEBASE_GUIDE.md @@ -4,7 +4,7 @@ The Void codebase is not as intimidating as it seems! Most of Void's code lives in the folder `src/vs/workbench/contrib/void/`. -The purpose of this document is to explain how Void's codebase works. If you want build instructions instead, see [Contributing](https://github.com/voideditor/void/blob/main/HOW_TO_CONTRIBUTE.md). +The purpose of this document is to explain how Void's codebase works. If you want build instructions instead, see [Contributing](https://github.com/voideditor-test/void/blob/main/HOW_TO_CONTRIBUTE.md). @@ -64,7 +64,7 @@ Sending LLM messages from the main process avoids CSP issues with local provider -**Notes:** `modelCapabilities` is an important file that must be updated when new models come out! +**Notes:** `modelCapabilities` is an important file that must be updated when new models come out! ### Apply @@ -74,16 +74,16 @@ Void has two types of Apply: **Fast Apply** (uses Search/Replace, see below), an When you click Apply and Fast Apply is enabled, we prompt the LLM to output Search/Replace block(s) like this: ``` <<<<<<< ORIGINAL -// original code goes here +// original code goes here ======= // replaced code goes here >>>>>>> UPDATED ``` -This is what allows Void to quickly apply code even on 1000-line files. It's the same as asking the LLM to press Ctrl+F and enter in a search/replace query. +This is what allows Void to quickly apply code even on 1000-line files. It's the same as asking the LLM to press Ctrl+F and enter in a search/replace query. ### Apply Inner Workings -The `editCodeService` file runs Apply. The same exact code is also used when the LLM calls the Edit tool, and when you submit Cmd+K. Just different versions of Fast/Slow Apply mode. +The `editCodeService` file runs Apply. The same exact code is also used when the LLM calls the Edit tool, and when you submit Cmd+K. Just different versions of Fast/Slow Apply mode. Here is some important terminology: - A **DiffZone** is a {startLine, endLine} region of text where we compute and show red/green areas, or **Diffs**. When any changes are made to a file, we loop through all the DiffAreas on that file and refresh its Diffs. @@ -110,7 +110,7 @@ Here's a guide to some of the terminology we're using: - **FeatureName**: Autocomplete | Chat | CtrlK | Apply - **ModelSelection**: a {providerName, modelName} pair. - **ProviderName**: The name of a provider: `'ollama'`, `'openAI'`, etc. -- **ModelName**: The name of a model (string type, eg `'gpt-4o'`). +- **ModelName**: The name of a model (string type, eg `'gpt-4o'`). - **RefreshProvider**: a provider that we ping repeatedly to update the models list. - **ChatMode** = normal | gather | agent @@ -126,7 +126,7 @@ Here's a guide to some of the terminology we're using: ### Build process -If you want to know how our build pipeline works, see our build repo [here](https://github.com/voideditor/void-builder). +If you want to know how our build pipeline works, see our build repo [here](https://github.com/voideditor-test/void-builder). diff --git a/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index 98175f53..311299c6 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -82,6 +82,7 @@ function buildWin32Setup(arch, target) { productJson['target'] = target; fs.writeFileSync(productJsonPath, JSON.stringify(productJson, undefined, '\t')); + console.log('RawVersion!!!!!!!!!!!!!!', pkg.version.replace(/-\w+$/, '')) // Void const quality = product.quality || 'dev'; const definitions = { NameLong: product.nameLong, diff --git a/extensions/open-remote-ssh/package.json b/extensions/open-remote-ssh/package.json index 04bd4ad8..16cef436 100644 --- a/extensions/open-remote-ssh/package.json +++ b/extensions/open-remote-ssh/package.json @@ -1,7 +1,7 @@ { "name": "open-remote-ssh", "displayName": "Open Remote - SSH", - "publisher": "voideditor", + "publisher": "voideditor-test", "description": "Use any remote machine with a SSH server as your development environment.", "version": "0.0.48", "icon": "resources/icon.png", @@ -71,7 +71,7 @@ "type": "string", "description": "The URL from where the vscode server will be downloaded. You can use the following variables and they will be replaced dynamically:\n- ${quality}: vscode server quality, e.g. stable or insiders\n- ${version}: vscode server version, e.g. 1.69.0\n- ${commit}: vscode server release commit\n- ${arch}: vscode server arch, e.g. x64, armhf, arm64\n- ${release}: release number", "scope": "application", - "default": "https://github.com/voideditor/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz" + "default": "https://github.com/voideditor-test/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz" }, "remote.SSH.remotePlatform": { "type": "object", diff --git a/extensions/open-remote-ssh/src/serverConfig.ts b/extensions/open-remote-ssh/src/serverConfig.ts index 2478df5d..2405b2a6 100644 --- a/extensions/open-remote-ssh/src/serverConfig.ts +++ b/extensions/open-remote-ssh/src/serverConfig.ts @@ -32,14 +32,12 @@ export async function getVSCodeServerConfig(): Promise { const customServerBinaryName = vscode.workspace.getConfiguration('remote.SSH.experimental').get('serverBinaryName', ''); return { - // version: vscode.version.replace('-insider', ''), + version: vscode.version.replace('-insider', ''), commit: productJson.commit, quality: productJson.quality, release: productJson.release, serverApplicationName: customServerBinaryName || productJson.serverApplicationName, serverDataFolderName: productJson.serverDataFolderName, serverDownloadUrlTemplate: productJson.serverDownloadUrlTemplate, - // Void changed this - version: productJson.voidVersion }; } diff --git a/extensions/open-remote-ssh/src/serverSetup.ts b/extensions/open-remote-ssh/src/serverSetup.ts index 31830223..772910fe 100644 --- a/extensions/open-remote-ssh/src/serverSetup.ts +++ b/extensions/open-remote-ssh/src/serverSetup.ts @@ -39,7 +39,7 @@ export class ServerInstallError extends Error { } } -const DEFAULT_DOWNLOAD_URL_TEMPLATE = 'https://github.com/voideditor/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz'; +const DEFAULT_DOWNLOAD_URL_TEMPLATE = 'https://github.com/voideditor-test/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz'; export async function installCodeServer(conn: SSHConnection, serverDownloadUrlTemplate: string | undefined, extensionIds: string[], envVariables: string[], platform: string | undefined, useSocketPath: boolean, logger: Log): Promise { let shell = 'powershell'; diff --git a/extensions/open-remote-wsl/package.json b/extensions/open-remote-wsl/package.json index e913bdd9..3414b9f4 100644 --- a/extensions/open-remote-wsl/package.json +++ b/extensions/open-remote-wsl/package.json @@ -38,7 +38,7 @@ "type": "string", "description": "The URL from where the vscode server will be downloaded. You can use the following variables and they will be replaced dynamically:\n- ${quality}: vscode server quality, e.g. stable or insiders\n- ${version}: vscode server version, e.g. 1.69.0\n- ${commit}: vscode server release commit\n- ${arch}: vscode server arch, e.g. x64, armhf, arm64\n- ${release}: release number", "scope": "application", - "default": "https://github.com/voideditor/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz" + "default": "https://github.com/voideditor-test/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz" } } }, diff --git a/extensions/open-remote-wsl/src/serverConfig.ts b/extensions/open-remote-wsl/src/serverConfig.ts index 83a73643..476350db 100644 --- a/extensions/open-remote-wsl/src/serverConfig.ts +++ b/extensions/open-remote-wsl/src/serverConfig.ts @@ -31,14 +31,12 @@ export async function getVSCodeServerConfig(): Promise { const productJson = await getVSCodeProductJson(); return { - // version: vscode.version.replace('-insider', ''), + version: vscode.version.replace('-insider', ''), commit: productJson.commit, quality: productJson.quality, release: productJson.release, serverApplicationName: productJson.serverApplicationName, serverDataFolderName: productJson.serverDataFolderName, serverDownloadUrlTemplate: productJson.serverDownloadUrlTemplate, - // Void changed this - version: productJson.voidVersion }; } diff --git a/extensions/open-remote-wsl/src/serverSetup.ts b/extensions/open-remote-wsl/src/serverSetup.ts index 3d254313..4c24da38 100644 --- a/extensions/open-remote-wsl/src/serverSetup.ts +++ b/extensions/open-remote-wsl/src/serverSetup.ts @@ -39,7 +39,7 @@ export class ServerInstallError extends Error { } } -const DEFAULT_DOWNLOAD_URL_TEMPLATE = 'https://github.com/voideditor/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz'; +const DEFAULT_DOWNLOAD_URL_TEMPLATE = 'https://github.com/voideditor-test/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz'; export async function installCodeServer(wslManager: WSLManager, distroName: string, serverDownloadUrlTemplate: string | undefined, extensionIds: string[], envVariables: string[], logger: Log): Promise { const scriptId = crypto.randomBytes(12).toString('hex'); diff --git a/package-lock.json b/package-lock.json index 5d86ec28..513936cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,14 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@anthropic-ai/sdk": "^0.39.0", + "@anthropic-ai/sdk": "^0.40.0", "@c4312/eventsource-umd": "^3.0.5", - "@floating-ui/react": "^0.27.5", - "@google/generative-ai": "^0.22.0", + "@floating-ui/react": "^0.27.8", + "@google/generative-ai": "^0.24.0", "@microsoft/1ds-core-js": "^3.2.13", "@microsoft/1ds-post-js": "^3.2.13", - "@mistralai/mistralai": "^1.5.0", - "@modelcontextprotocol/sdk": "^1.9.0", + "@mistralai/mistralai": "^1.6.0", + "@modelcontextprotocol/sdk": "^1.10.2", "@parcel/watcher": "2.5.1", "@types/semver": "^7.5.8", "@vscode/deviceid": "^0.1.1", @@ -43,28 +43,28 @@ "@xterm/addon-webgl": "^0.19.0-beta.99", "@xterm/headless": "^5.6.0-beta.99", "@xterm/xterm": "^5.6.0-beta.99", + "ajv": "^8.17.1", "cross-spawn": "^7.0.6", "diff": "^7.0.0", - "eslint-plugin-react": "^7.37.4", - "groq-sdk": "^0.15.0", + "eslint-plugin-react": "^7.37.5", + "groq-sdk": "^0.20.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", - "katex": "^0.16.22", "kerberos": "2.1.1", - "lucide-react": "^0.477.0", - "marked": "^15.0.7", + "lucide-react": "^0.503.0", + "marked": "^15.0.11", "minimist": "^1.2.6", "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", "node-pty": "^1.1.0-beta33", - "ollama": "^0.5.14", + "ollama": "^0.5.15", "open": "^8.4.2", - "openai": "^4.86.1", - "posthog-node": "^4.8.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "openai": "^4.96.0", + "posthog-node": "^4.14.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", "react-tooltip": "^5.28.1", "tas-client-umd": "0.2.0", "v8-inspect-profiler": "^0.1.1", @@ -80,17 +80,16 @@ "@tailwindcss/typography": "^0.5.16", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", - "@types/diff": "^7.0.1", + "@types/diff": "^7.0.2", "@types/eslint": "^9.6.1", "@types/gulp-svgmin": "^1.2.1", "@types/http-proxy-agent": "^2.0.1", - "@types/katex": "^0.16.7", "@types/kerberos": "^1.1.2", "@types/minimist": "^1.2.1", "@types/mocha": "^9.1.1", "@types/node": "20.x", - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", "@types/sinon": "^10.0.2", "@types/sinon-test": "^2.4.2", "@types/trusted-types": "^1.0.6", @@ -160,8 +159,8 @@ "mocha": "^10.8.2", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", - "next": "^15.2.0", - "nodemon": "^3.1.9", + "next": "^15.3.1", + "nodemon": "^3.1.10", "npm-run-all": "^4.1.5", "original-fs": "^1.2.0", "os-browserify": "^0.3.0", @@ -184,7 +183,7 @@ "tsec": "0.2.7", "tslib": "^2.6.3", "tsup": "^8.4.0", - "typescript": "^5.8.2", + "typescript": "^5.8.0-dev.20250207", "typescript-eslint": "^8.8.0", "util": "^0.12.4", "webpack": "^5.94.0", @@ -224,9 +223,9 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.39.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.39.0.tgz", - "integrity": "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==", + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.40.0.tgz", + "integrity": "sha512-NkIgtZxa4nWBzXtDuYe6Wumu1+cgEuEQtol8b1bVSjtS7Dvqex6iNdxaddV8PkRC8Z8mhbNw2m7j+9AD9uRRKw==", "license": "MIT", "dependencies": { "@types/node": "^18.11.18", @@ -239,9 +238,9 @@ } }, "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { - "version": "18.19.86", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", - "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", + "version": "18.19.87", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.87.tgz", + "integrity": "sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -1216,9 +1215,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", "cpu": [ "ppc64" ], @@ -1233,9 +1232,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", "cpu": [ "arm" ], @@ -1250,9 +1249,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", "cpu": [ "arm64" ], @@ -1267,9 +1266,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", "cpu": [ "x64" ], @@ -1284,9 +1283,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", "cpu": [ "arm64" ], @@ -1301,9 +1300,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", "cpu": [ "x64" ], @@ -1318,9 +1317,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", "cpu": [ "arm64" ], @@ -1335,9 +1334,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", "cpu": [ "x64" ], @@ -1352,9 +1351,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", "cpu": [ "arm" ], @@ -1369,9 +1368,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", "cpu": [ "arm64" ], @@ -1386,9 +1385,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", "cpu": [ "ia32" ], @@ -1403,9 +1402,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", "cpu": [ "loong64" ], @@ -1420,9 +1419,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", "cpu": [ "mips64el" ], @@ -1437,9 +1436,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", "cpu": [ "ppc64" ], @@ -1454,9 +1453,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", "cpu": [ "riscv64" ], @@ -1471,9 +1470,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", "cpu": [ "s390x" ], @@ -1488,9 +1487,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", "cpu": [ "x64" ], @@ -1505,9 +1504,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", "cpu": [ "arm64" ], @@ -1522,9 +1521,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", "cpu": [ "x64" ], @@ -1539,9 +1538,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", "cpu": [ "arm64" ], @@ -1556,9 +1555,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", "cpu": [ "x64" ], @@ -1573,9 +1572,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", "cpu": [ "x64" ], @@ -1590,9 +1589,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", "cpu": [ "arm64" ], @@ -1607,9 +1606,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", "cpu": [ "ia32" ], @@ -1624,9 +1623,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", "cpu": [ "x64" ], @@ -1710,6 +1709,30 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/js": { "version": "9.11.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.1.tgz", @@ -1760,9 +1783,9 @@ } }, "node_modules/@floating-ui/react": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.7.tgz", - "integrity": "sha512-5V9pwFeiv+95Jlowq/7oiGISSrdXMTs2jfoSy8k+WM6oI/Skm1WWjPdJWeporN2O4UGcsaCJdirKffKayMoPgw==", + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.8.tgz", + "integrity": "sha512-EQJ4Th328y2wyHR3KzOUOoTW2UKjFk53fmyahfwExnFQ8vnsMYqKc+fFPOkeYtj5tcp1DUMiNJ7BFhed7e9ONw==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.1.2", @@ -1794,9 +1817,9 @@ "license": "MIT" }, "node_modules/@google/generative-ai": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.22.0.tgz", - "integrity": "sha512-mLR3PDWCk5O/BWNyDvFDIiwKeXQmFGZ+kJFd9m73QrUPCFREttJyVbBPTW4y9CwTbaltLMDaLDfroCrRv5Bl8Q==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.0.tgz", + "integrity": "sha512-fnEITCGEB7NdX0BhoYZ/cq/7WPZ1QS5IzJJfC3Tg/OwkvBetMiVJciyaan297OvE4B9Jg1xvo0zIazX/9sGu1Q==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -2583,9 +2606,9 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.10.1.tgz", - "integrity": "sha512-xNYdFdkJqEfIaTVP1gPKoEvluACHZsHZegIoICX8DM1o6Qf3G5u2BQJHmgd0n4YgRPqqK/u1ujQvrgAxxSJT9w==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.10.2.tgz", + "integrity": "sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==", "license": "MIT", "dependencies": { "content-type": "^1.0.5", @@ -3912,13 +3935,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/katex": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz", - "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/kerberos": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/kerberos/-/kerberos-1.1.2.tgz", @@ -5183,15 +5199,15 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -5215,28 +5231,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -5866,9 +5860,9 @@ } }, "node_modules/axios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", - "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -6555,16 +6549,11 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -6577,6 +6566,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -7341,6 +7333,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -7906,9 +7899,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "license": "Apache-2.0", "engines": { "node": ">=8" @@ -8176,9 +8169,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.139", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.139.tgz", - "integrity": "sha512-GGnRYOTdN5LYpwbIr0rwP/ZHOQSvAF6TG0LSzp28uCBb9JiXHJGmaaKw29qjNJc5bGnnp6kXJqRnGMQoELwi5w==", + "version": "1.5.143", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.143.tgz", + "integrity": "sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g==", "dev": true, "license": "ISC" }, @@ -8509,9 +8502,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -8522,31 +8515,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" } }, "node_modules/escalade": { @@ -8794,6 +8787,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", @@ -8818,6 +8828,13 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/esniff": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", @@ -9439,8 +9456,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-fifo": { "version": "1.3.2", @@ -9468,7 +9484,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -9476,6 +9493,22 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", @@ -9546,6 +9579,30 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/file-loader/node_modules/schema-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", @@ -10936,9 +10993,9 @@ "dev": true }, "node_modules/groq-sdk": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/groq-sdk/-/groq-sdk-0.15.0.tgz", - "integrity": "sha512-aYDEdr4qczx3cLCRRe+Beb37I7g/9bD5kHF+EEDxcrREWw1vKoRcfP3vHEkJB7Ud/8oOuF0scRwDpwWostTWuQ==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/groq-sdk/-/groq-sdk-0.20.1.tgz", + "integrity": "sha512-I/U7mHDcanKHR/P0oKSSS0M6oHR69G1QgtMplqmF3gSejJ5ihV7l+/0OqbNoqOzYoQKG4XH7O4zCqMoTKCztQQ==", "license": "Apache-2.0", "dependencies": { "@types/node": "^18.11.18", @@ -10951,9 +11008,9 @@ } }, "node_modules/groq-sdk/node_modules/@types/node": { - "version": "18.19.86", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", - "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", + "version": "18.19.87", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.87.tgz", + "integrity": "sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -13937,10 +13994,10 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -14038,31 +14095,6 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, - "node_modules/katex": { - "version": "0.16.22", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", - "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" - ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" - }, - "bin": { - "katex": "cli.js" - } - }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/kerberos": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-2.1.1.tgz", @@ -14636,9 +14668,9 @@ } }, "node_modules/lucide-react": { - "version": "0.477.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.477.0.tgz", - "integrity": "sha512-yCf7aYxerFZAbd8jHJxjwe1j7jEMPptjnaOqdYeirFnEy85cNR3/L+o0I875CYFYya+eEVzZSbNuRk8BZPDpVw==", + "version": "0.503.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.503.0.tgz", + "integrity": "sha512-HGGkdlPWQ0vTF8jJ5TdIqhQXZi6uh3LnNgfZ8MHiuxFfX3RZeA79r2MW2tHAZKlAVfoNE8esm3p+O6VkIvpj6w==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -14731,9 +14763,9 @@ } }, "node_modules/marked": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.8.tgz", - "integrity": "sha512-rli4l2LyZqpQuRve5C0rkn6pj3hT8EWPC+zkAxFTAJLxRbENfTAhEQq9itrmf1Y81QtAX5D/MYlGlIomNgj9lA==", + "version": "15.0.11", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.11.tgz", + "integrity": "sha512-1BEXAU2euRCG3xwgLVT1y0xbJEld1XOrmRJpUwRCcy7rxhSCwMrmEu9LXoPhHSCJG41V7YcQ2mjKRr5BA3ITIA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -15866,9 +15898,9 @@ "license": "MIT" }, "node_modules/nodemon": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", - "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", "dev": true, "license": "MIT", "dependencies": { @@ -16495,9 +16527,9 @@ } }, "node_modules/openai": { - "version": "4.95.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.95.1.tgz", - "integrity": "sha512-IqJy+ymeW+k/Wq+2YVN3693OQMMcODRtHEYOlz263MdUwnN/Dwdl9c2EXSxLLtGEHkSHAfvzpDMHI5MaWJKXjQ==", + "version": "4.96.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.96.0.tgz", + "integrity": "sha512-dKoW56i02Prv2XQolJ9Rl9Svqubqkzg3QpwEOBuSVZLk05Shelu7s+ErRTwFc1Bs3JZ2qBqBfVpXQiJhwOGG8A==", "license": "Apache-2.0", "dependencies": { "@types/node": "^18.11.18", @@ -16525,9 +16557,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.86", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", - "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", + "version": "18.19.87", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.87.tgz", + "integrity": "sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -17498,9 +17530,9 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "dev": true, "funding": [ { @@ -17514,21 +17546,28 @@ ], "license": "MIT", "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 14" + "node": ">= 18" }, "peerDependencies": { + "jiti": ">=1.21.0", "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { + "jiti": { + "optional": true + }, "postcss": { "optional": true }, - "ts-node": { + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } @@ -18101,9 +18140,9 @@ "dev": true }, "node_modules/posthog-node": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.12.0.tgz", - "integrity": "sha512-YWib8aiPXcICAZa29ZuLyjFaJE8dbxbd+v2apoIEPbyMqOra9bKPYVI8XK15Q44vflaaCOOAtTV8A9DefZSbVQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-4.14.0.tgz", + "integrity": "sha512-PitSiuxGiVFl0ItuhIfi3Sq1tcaMU4vlbPu1wv0qufTJGDjWthOOr4vYfFIs1xkbJFOQcfGczMXkr44kX5TDDg==", "license": "MIT", "dependencies": { "axios": "^1.8.2" @@ -18916,7 +18955,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -19391,22 +19429,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/schema-utils/node_modules/ajv-keywords": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", @@ -19419,12 +19441,6 @@ "ajv": "^8.8.2" } }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/scope-tailwind": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/scope-tailwind/-/scope-tailwind-1.0.9.tgz", @@ -21301,44 +21317,6 @@ "dev": true, "license": "MIT" }, - "node_modules/tailwindcss/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/tailwindcss/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -21352,6 +21330,42 @@ "node": ">=10.13.0" } }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, "node_modules/tailwindcss/node_modules/postcss-nested": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", @@ -21521,6 +21535,30 @@ } } }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -22136,49 +22174,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/tsup/node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, "node_modules/tsup/node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -22386,9 +22381,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.8.0-dev.20250207", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.0-dev.20250207.tgz", + "integrity": "sha512-bRCO1GkVxTLd/UFJWOg9R1oRiSMidcfpICzuQlDJlHspv6hlcJvvIJP0BvQxrBYpu4dbzqp/Fh8rRYIkEjbSlQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -22757,6 +22752,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -23317,6 +23313,23 @@ "node": ">= 0.10" } }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -23339,6 +23352,13 @@ "node": ">=4.0" } }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", diff --git a/package.json b/package.json index fcf0714a..23de71cf 100644 --- a/package.json +++ b/package.json @@ -72,14 +72,14 @@ "update-build-ts-version": "npm install typescript@next && tsc -p ./build/tsconfig.build.json" }, "dependencies": { - "@anthropic-ai/sdk": "^0.39.0", - "@floating-ui/react": "^0.27.5", - "@google/generative-ai": "^0.22.0", + "@anthropic-ai/sdk": "^0.40.0", "@c4312/eventsource-umd": "^3.0.5", + "@floating-ui/react": "^0.27.8", + "@google/generative-ai": "^0.24.0", "@microsoft/1ds-core-js": "^3.2.13", "@microsoft/1ds-post-js": "^3.2.13", - "@mistralai/mistralai": "^1.5.0", - "@modelcontextprotocol/sdk": "^1.9.0", + "@mistralai/mistralai": "^1.6.0", + "@modelcontextprotocol/sdk": "^1.10.2", "@parcel/watcher": "2.5.1", "@types/semver": "^7.5.8", "@vscode/deviceid": "^0.1.1", @@ -105,28 +105,28 @@ "@xterm/addon-webgl": "^0.19.0-beta.99", "@xterm/headless": "^5.6.0-beta.99", "@xterm/xterm": "^5.6.0-beta.99", + "ajv": "^8.17.1", "cross-spawn": "^7.0.6", "diff": "^7.0.0", - "eslint-plugin-react": "^7.37.4", - "groq-sdk": "^0.15.0", + "eslint-plugin-react": "^7.37.5", + "groq-sdk": "^0.20.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.4", - "katex": "^0.16.22", "kerberos": "2.1.1", - "lucide-react": "^0.477.0", - "marked": "^15.0.7", + "lucide-react": "^0.503.0", + "marked": "^15.0.11", "minimist": "^1.2.6", "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", "node-pty": "^1.1.0-beta33", - "ollama": "^0.5.14", + "ollama": "^0.5.15", "open": "^8.4.2", - "openai": "^4.86.1", - "posthog-node": "^4.8.1", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "openai": "^4.96.0", + "posthog-node": "^4.14.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", "react-tooltip": "^5.28.1", "tas-client-umd": "0.2.0", "v8-inspect-profiler": "^0.1.1", @@ -142,17 +142,16 @@ "@tailwindcss/typography": "^0.5.16", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", - "@types/diff": "^7.0.1", + "@types/diff": "^7.0.2", "@types/eslint": "^9.6.1", "@types/gulp-svgmin": "^1.2.1", "@types/http-proxy-agent": "^2.0.1", - "@types/katex": "^0.16.7", "@types/kerberos": "^1.1.2", "@types/minimist": "^1.2.1", "@types/mocha": "^9.1.1", "@types/node": "20.x", - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", "@types/sinon": "^10.0.2", "@types/sinon-test": "^2.4.2", "@types/trusted-types": "^1.0.6", @@ -222,8 +221,8 @@ "mocha": "^10.8.2", "mocha-junit-reporter": "^2.2.1", "mocha-multi-reporters": "^1.5.1", - "next": "^15.2.0", - "nodemon": "^3.1.9", + "next": "^15.3.1", + "nodemon": "^3.1.10", "npm-run-all": "^4.1.5", "original-fs": "^1.2.0", "os-browserify": "^0.3.0", @@ -246,7 +245,7 @@ "tsec": "0.2.7", "tslib": "^2.6.3", "tsup": "^8.4.0", - "typescript": "^5.8.2", + "typescript": "^5.8.0-dev.20250207", "typescript-eslint": "^8.8.0", "util": "^0.12.4", "webpack": "^5.94.0", diff --git a/product.json b/product.json index ab61205d..352c2931 100644 --- a/product.json +++ b/product.json @@ -1,13 +1,13 @@ { "nameShort": "Void", "nameLong": "Void", - "voidVersion": "1.2.6", + "voidVersion": "1.2.8", "applicationName": "void", "dataFolderName": ".void-editor", - "win32MutexName": "voideditor", + "win32MutexName": "voideditor-test", "licenseName": "MIT", - "licenseUrl": "https://github.com/voideditor/void/blob/main/LICENSE.txt", - "serverLicenseUrl": "https://github.com/voideditor/void/blob/main/LICENSE.txt", + "licenseUrl": "https://github.com/voideditor-test/void/blob/main/LICENSE.txt", + "serverLicenseUrl": "https://github.com/voideditor-test/void/blob/main/LICENSE.txt", "serverGreeting": [], "serverLicense": [], "serverLicensePrompt": "", @@ -25,10 +25,10 @@ "win32ShellNameShort": "V&oid", "win32TunnelServiceMutex": "void-tunnelservice", "win32TunnelMutex": "void-tunnel", - "darwinBundleIdentifier": "com.voideditor.code", + "darwinBundleIdentifier": "com.voideditor-test.code", "linuxIconName": "void-editor", "licenseFileName": "LICENSE.txt", - "reportIssueUrl": "https://github.com/voideditor/void/issues/new", + "reportIssueUrl": "https://github.com/voideditor-test/void/issues/new", "nodejsRepository": "https://nodejs.org", "urlProtocol": "void", "extensionsGallery": { @@ -37,7 +37,7 @@ }, "builtInExtensions": [], "linkProtectionTrustedDomains": [ - "https://voideditor.com", - "https://voideditor.dev" + "https://voideditor-test.com", + "https://voideditor-test.dev" ] } diff --git a/resources/darwin/code.icns b/resources/darwin/code.icns index a91b7c58..1fa6e9d0 100644 Binary files a/resources/darwin/code.icns and b/resources/darwin/code.icns differ diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index 1cbe1a2a..9584b400 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -57,8 +57,8 @@ export type ExtensionVirtualWorkspaceSupport = { export interface IProductConfiguration { readonly version: string; - readonly voidVersion: string; // Void added this - readonly release: string; // VSCodium added this + readonly voidVersion?: string; + readonly release?: string; // Void - VSCodium added this, we add it for TS readonly date?: string; readonly quality?: string; readonly commit?: string; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index 13274ccc..4fb4ed8e 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -21,7 +21,7 @@ import { SuggestController } from '../../../../../editor/contrib/suggest/browser import { localize, localize2 } from '../../../../../nls.js'; import { IActionViewItemService } from '../../../../../platform/actions/browser/actionViewItemService.js'; import { DropdownWithPrimaryActionViewItem } from '../../../../../platform/actions/browser/dropdownWithPrimaryActionViewItem.js'; -import { Action2, MenuId, MenuItemAction, MenuRegistry, registerAction2, SubmenuItemAction } from '../../../../../platform/actions/common/actions.js'; +import { Action2, MenuId, MenuItemAction, registerAction2, SubmenuItemAction } from '../../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts b/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts index 4f5e28a3..1ab3540a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts @@ -4,43 +4,43 @@ *--------------------------------------------------------------------------------------------*/ import { coalesce, isNonEmptyArray } from '../../../../base/common/arrays.js'; -import { Codicon } from '../../../../base/common/codicons.js'; +// import { Codicon } from '../../../../base/common/codicons.js'; import { toErrorMessage } from '../../../../base/common/errorMessage.js'; import { Event } from '../../../../base/common/event.js'; import { MarkdownString } from '../../../../base/common/htmlContent.js'; -import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; +// import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js'; import { Disposable, DisposableMap, DisposableStore } from '../../../../base/common/lifecycle.js'; import * as strings from '../../../../base/common/strings.js'; -import { URI } from '../../../../base/common/uri.js'; -import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; -import { localize, localize2 } from '../../../../nls.js'; -import { CommandsRegistry } from '../../../../platform/commands/common/commands.js'; -import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; -import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +// import { URI } from '../../../../base/common/uri.js'; +// import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js'; +import { localize } from '../../../../nls.js'; +// import { CommandsRegistry } from '../../../../platform/commands/common/commands.js'; +// import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; +import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { ExtensionIdentifier, IExtensionManifest } from '../../../../platform/extensions/common/extensions.js'; import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js'; import { ILogService } from '../../../../platform/log/common/log.js'; -import { IOpenerService } from '../../../../platform/opener/common/opener.js'; +// import { IOpenerService } from '../../../../platform/opener/common/opener.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; import { Registry } from '../../../../platform/registry/common/platform.js'; -import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; -import { ViewPane } from '../../../browser/parts/views/viewPane.js'; -import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContainer.js'; -import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; -import { IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation, Extensions as ViewExtensions } from '../../../common/views.js'; +// import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; +// import { ViewPane } from '../../../browser/parts/views/viewPane.js'; +// import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContainer.js'; +import { IWorkbenchContribution, } from '../../../common/contributions.js'; +import { IViewsRegistry, Extensions as ViewExtensions } from '../../../common/views.js'; import { Extensions, IExtensionFeaturesRegistry, IExtensionFeatureTableRenderer, IRenderedData, IRowData, ITableData } from '../../../services/extensionManagement/common/extensionFeatures.js'; import { isProposedApiEnabled } from '../../../services/extensions/common/extensions.js'; import * as extensionsRegistry from '../../../services/extensions/common/extensionsRegistry.js'; -import { IViewsService } from '../../../services/views/common/viewsService.js'; +// import { IViewsService } from '../../../services/views/common/viewsService.js'; import { showExtensionsWithIdsCommandId } from '../../extensions/browser/extensionsActions.js'; import { IExtension, IExtensionsWorkbenchService } from '../../extensions/common/extensions.js'; import { IChatAgentData, IChatAgentService } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { IRawChatParticipantContribution } from '../common/chatParticipantContribTypes.js'; -import { IChatService } from '../common/chatService.js'; -import { ChatAgentLocation, ChatConfiguration } from '../common/constants.js'; -import { ChatViewId, showChatView } from './chat.js'; -import { CHAT_EDITING_SIDEBAR_PANEL_ID, CHAT_SIDEBAR_PANEL_ID, ChatViewPane } from './chatViewPane.js'; +// import { IChatService } from '../common/chatService.js'; +import { ChatAgentLocation } from '../common/constants.js'; +import { ChatViewId } from './chat.js'; +// import { CHAT_EDITING_SIDEBAR_PANEL_ID, CHAT_SIDEBAR_PANEL_ID, ChatViewPane } from './chatViewPane.js'; // --- Chat Container & View Registration diff --git a/src/vs/workbench/contrib/void/browser/autocompleteService.ts b/src/vs/workbench/contrib/void/browser/autocompleteService.ts index 95ec65c2..3137e4f3 100644 --- a/src/vs/workbench/contrib/void/browser/autocompleteService.ts +++ b/src/vs/workbench/contrib/void/browser/autocompleteService.ts @@ -28,7 +28,7 @@ import { IConvertToLLMMessageService } from './convertToLLMMessageService.js'; const allLinebreakSymbols = ['\r\n', '\n'] const _ln = isWindows ? allLinebreakSymbols[0] : allLinebreakSymbols[1] -// The extension this was called from is here - https://github.com/voideditor/void/blob/autocomplete/extensions/void/src/extension/extension.ts +// The extension this was called from is here - https://github.com/voideditor-test/void/blob/autocomplete/extensions/void/src/extension/extension.ts /* diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts index 7a09327d..e43b3527 100644 --- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts +++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts @@ -34,6 +34,7 @@ import { THREAD_STORAGE_KEY } from '../common/storageKeys.js'; import { IConvertToLLMMessageService } from './convertToLLMMessageService.js'; import { timeout } from '../../../../base/common/async.js'; import { deepClone } from '../../../../base/common/objects.js'; +import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; // related to retrying when LLM message has error @@ -140,15 +141,39 @@ export type IsRunningType = export type ThreadStreamState = { [threadId: string]: undefined | { - // state related to streaming (not just when streaming) - isRunning?: IsRunningType; // whether or not actually running the agent loop (can be running and not streaming, like if it's calling a tool and awaiting user response) + isRunning: undefined; error?: { message: string, fullError: Error | null, }; - - // streaming related - when streaming message - streamingToken?: string; - displayContentSoFar?: string; - reasoningSoFar?: string; - toolCallSoFar?: RawToolCallObj; + llmInfo?: undefined; + toolInfo?: undefined; + interrupt?: undefined; + } | { // an assistant message is being written + isRunning: 'LLM'; + error?: undefined; + llmInfo: { + displayContentSoFar: string; + reasoningSoFar: string; + toolCallSoFar: RawToolCallObj | null; + }; + toolInfo?: undefined; + interrupt: Promise<() => void>; // calling this should have no effect on state - would be too confusing. it just cancels the tool + } | { // a tool is being run + isRunning: 'tool'; + error?: undefined; + llmInfo?: undefined; + toolInfo: { + toolName: ToolName; + toolParams: ToolCallParams[ToolName]; + id: string; + content: string; + rawParams: RawToolParamsObj; + }; + interrupt: Promise<() => void>; + } | { + isRunning: 'awaiting_user'; + error?: undefined; + llmInfo?: undefined; + toolInfo?: undefined; + interrupt?: undefined; } } @@ -213,10 +238,11 @@ export interface IChatThreadService { // codespan links (link to symbols in the markdown) getCodespanLink(opts: { codespanStr: string, messageIdx: number, threadId: string }): CodespanLocationLink | undefined; addCodespanLink(opts: { newLinkText: string, newLinkLocation: CodespanLocationLink, messageIdx: number, threadId: string }): void; - generateCodespanLink(opts: { codespanStr: string, threadId: string }): Promise + generateCodespanLink(opts: { codespanStr: string, threadId: string }): Promise; + getRelativeStr(uri: URI): string | undefined // entry pts - stopRunning(threadId: string): void; + abortRunning(threadId: string): Promise; dismissStreamError(threadId: string): void; // call to edit a message @@ -263,6 +289,7 @@ class ChatThreadService extends Disposable implements IChatThreadService { @IEditCodeService private readonly _editCodeService: IEditCodeService, @INotificationService private readonly _notificationService: INotificationService, @IConvertToLLMMessageService private readonly _convertToLLMMessagesService: IConvertToLLMMessageService, + @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, ) { super() this.state = { allThreads: {}, currentThreadId: null as unknown as string } // default state @@ -341,32 +368,41 @@ class ChatThreadService extends Disposable implements IChatThreadService { // this should be the only place this.state = ... appears besides constructor private _setState(state: Partial, affectsCurrent: boolean) { - this.state = { + const newState = { ...this.state, ...state } + + this.state = newState + if (affectsCurrent) this._onDidChangeCurrentThread.fire() + + + // if we just switched to a thread, update its current stream state if it's not streaming to possibly streaming + const threadId = newState.currentThreadId + const streamState = this.streamState[threadId] + if (streamState?.isRunning === undefined && !streamState?.error) { + + // set streamState + const messages = newState.allThreads[threadId]?.messages + const lastMessage = messages && messages[messages.length - 1] + // if awaiting user but stream state doesn't indicate it (happens if restart Void) + if (lastMessage && lastMessage.role === 'tool' && lastMessage.type === 'tool_request') + this._setStreamState(threadId, { isRunning: 'awaiting_user', }) + + // if running now but stream state doesn't indicate it (happens if restart Void), cancel that last tool + if (lastMessage && lastMessage.role === 'tool' && lastMessage.type === 'running_now') { + this._updateLatestTool(threadId, { role: 'tool', type: 'rejected', content: lastMessage.content, id: lastMessage.id, rawParams: lastMessage.rawParams, result: null, name: lastMessage.name, params: lastMessage.params }) + } + + } + } - private _setStreamState(threadId: string, state: Partial>, behavior: 'set' | 'merge') { - if (state === undefined) - delete this.streamState[threadId] - - else { - if (behavior === 'merge') { - this.streamState[threadId] = { - ...this.streamState[threadId], - ...state - } - } - else if (behavior === 'set') { - this.streamState[threadId] = state - } - else throw new Error(`setStreamState`) - } - + private _setStreamState(threadId: string, state: ThreadStreamState[string]) { + this.streamState[threadId] = state this._onDidChangeStreamState.fire({ threadId }) } @@ -433,40 +469,35 @@ class ChatThreadService extends Disposable implements IChatThreadService { const errorMessage = this.errMsgs.rejected this._updateLatestTool(threadId, { role: 'tool', type: 'rejected', params: params, name: name, content: errorMessage, result: null, id, rawParams }) - this._setStreamState(threadId, {}, 'set') + this._setStreamState(threadId, undefined) } - stopRunning(threadId: string) { + async abortRunning(threadId: string) { const thread = this.state.allThreads[threadId] if (!thread) return // should never happen - // reject the tool for the user if relevant - this.rejectLatestToolRequest(threadId) - - // interrupt the tool if relevant - this._currentlyRunningToolInterruptor[threadId]?.() - - // interrupt assistant message - const isRunning = this.streamState[threadId]?.isRunning - if (isRunning === 'LLM') { - // abort the stream first so it doesn't change any state - const displayContentSoFar = this.streamState[threadId]?.displayContentSoFar ?? '' - const reasoningSoFar = this.streamState[threadId]?.reasoningSoFar ?? '' - const toolCallSoFar = this.streamState[threadId]?.toolCallSoFar - - const llmCancelToken = this.streamState[threadId]?.streamingToken - if (llmCancelToken !== undefined) { this._llmMessageService.abort(llmCancelToken) } + // interrupt any effects + const interrupt = await this.streamState[threadId]?.interrupt + interrupt?.() + // add assistant message + if (this.streamState[threadId]?.isRunning === 'LLM') { + const { displayContentSoFar, reasoningSoFar, toolCallSoFar } = this.streamState[threadId].llmInfo this._addMessageToThread(threadId, { role: 'assistant', displayContent: displayContentSoFar, reasoning: reasoningSoFar, anthropicReasoning: null }) - - if (toolCallSoFar) { - this._addMessageToThread(threadId, { role: 'interrupted_streaming_tool', name: toolCallSoFar.name }) - } - + if (toolCallSoFar) this._addMessageToThread(threadId, { role: 'interrupted_streaming_tool', name: toolCallSoFar.name }) this._addUserCheckpoint({ threadId }) } + // add tool that's running + else if (this.streamState[threadId]?.isRunning === 'tool') { + const { toolName, toolParams, id, content, rawParams } = this.streamState[threadId].toolInfo + this._updateLatestTool(threadId, { role: 'tool', name: toolName, params: toolParams, id, content, rawParams, type: 'rejected', result: null }) + } + // reject the tool for the user if relevant + else if (this.streamState[threadId]?.isRunning === 'awaiting_user') { + this.rejectLatestToolRequest(threadId) + } - this._setStreamState(threadId, {}, 'set') + this._setStreamState(threadId, undefined) } @@ -477,7 +508,7 @@ class ChatThreadService extends Disposable implements IChatThreadService { } - private readonly _currentlyRunningToolInterruptor: { [threadId: string]: (() => void) | undefined } = {} + // private readonly _currentlyRunningToolInterruptor: { [threadId: string]: (() => void) | undefined } = {} // returns true when the tool call is waiting for user approval @@ -496,7 +527,7 @@ class ChatThreadService extends Disposable implements IChatThreadService { if (!opts.preapproved) { // skip this if pre-approved // 1. validate tool params try { - const params = await this._toolsService.validateParams[toolName](opts.unvalidatedToolParams) + const params = this._toolsService.validateParams[toolName](opts.unvalidatedToolParams) toolParams = params } catch (error) { const errorMessage = getErrorMessage(error) @@ -526,30 +557,38 @@ class ChatThreadService extends Disposable implements IChatThreadService { // 3. call the tool - this._setStreamState(threadId, { isRunning: 'tool' }, 'merge') - this._updateLatestTool(threadId, { role: 'tool', type: 'running_now', name: toolName, params: toolParams, content: '(value not received yet...)', result: null, id: toolId, rawParams: opts.unvalidatedToolParams }) + // this._setStreamState(threadId, { isRunning: 'tool' }, 'merge') + const runningTool = { role: 'tool', type: 'running_now', name: toolName, params: toolParams, content: '(value not received yet...)', result: null, id: toolId, rawParams: opts.unvalidatedToolParams } as const + this._updateLatestTool(threadId, runningTool) + let interrupted = false + let resolveInterruptor: (r: () => void) => void = () => { } + const interruptorPromise = new Promise<() => void>(res => { resolveInterruptor = res }) try { + + // set stream state + this._setStreamState(threadId, { isRunning: 'tool', interrupt: interruptorPromise, toolInfo: { toolName, toolParams, id: toolId, content: 'interrupted...', rawParams: opts.unvalidatedToolParams } }) + const { result, interruptTool } = await this._toolsService.callTool[toolName](toolParams as any) - this._currentlyRunningToolInterruptor[threadId] = () => { - interrupted = true; - interruptTool?.(); - delete this._currentlyRunningToolInterruptor[threadId]; - } - toolResult = await result // ts is bad... await is needed + const interruptor = () => { interrupted = true; interruptTool?.() } + resolveInterruptor(interruptor) + + toolResult = await result if (interrupted) { return { interrupted: true } } // the tool result is added where we interrupt, not here } catch (error) { - delete this._currentlyRunningToolInterruptor[threadId] + resolveInterruptor(() => { }) // resolve for the sake of it if (interrupted) { return { interrupted: true } } // the tool result is added where we interrupt, not here - const errorMessage = getErrorMessage(error) this._updateLatestTool(threadId, { role: 'tool', type: 'tool_error', params: toolParams, result: errorMessage, name: toolName, content: errorMessage, id: toolId, rawParams: opts.unvalidatedToolParams }) return {} } + finally { + this._setStreamState(threadId, undefined) + } // 4. stringify the result to give to the LLM try { @@ -562,8 +601,6 @@ class ChatThreadService extends Disposable implements IChatThreadService { // 5. add to history and keep going this._updateLatestTool(threadId, { role: 'tool', type: 'success', params: toolParams, result: toolResult, name: toolName, content: toolResultStr, id: toolId, rawParams: opts.unvalidatedToolParams }) - delete this._currentlyRunningToolInterruptor[threadId] - return {} }; @@ -587,8 +624,8 @@ class ChatThreadService extends Disposable implements IChatThreadService { // above just defines helpers, below starts the actual function const { chatMode } = this._settingsService.state.globalSettings // should not change as we loop even if user changes it, so it goes here - // clear any previous error - this._setStreamState(threadId, { error: undefined }, 'set') + // not running at start, clear state + this._setStreamState(threadId, undefined) let nMessagesSent = 0 let shouldSendAnotherMessage = true @@ -597,7 +634,8 @@ class ChatThreadService extends Disposable implements IChatThreadService { // before enter loop, call tool if (callThisToolFirst) { const { interrupted } = await this._runToolCall(threadId, callThisToolFirst.name, callThisToolFirst.id, { preapproved: true, unvalidatedToolParams: callThisToolFirst.rawParams, validatedParams: callThisToolFirst.params }) - if (interrupted) return + this._setStreamState(threadId, undefined) + if (interrupted) { return } } // tool use loop @@ -618,14 +656,16 @@ class ChatThreadService extends Disposable implements IChatThreadService { let shouldRetry = true let nAttempts = 0 while (shouldRetry) { + if (this.streamState[threadId]?.isRunning) { + // if already streaming, stop + console.log('returning...', this.streamState[threadId]) + return + } shouldRetry = false let resMessageIsDonePromise: (toolCall?: RawToolCallObj | undefined) => void // resolves when user approves this tool use (or if tool doesn't require approval) const messageIsDonePromise = new Promise((res, rej) => { resMessageIsDonePromise = res }) - // send llm message - this._setStreamState(threadId, { isRunning: 'LLM' }, 'merge') - const llmCancelToken = this._llmMessageService.sendLLMMessage({ messagesType: 'chatMessages', chatMode, @@ -635,84 +675,79 @@ class ChatThreadService extends Disposable implements IChatThreadService { logging: { loggingName: `Chat - ${chatMode}`, loggingExtras: { threadId, nMessagesSent, chatMode } }, separateSystemMessage: separateSystemMessage, onText: ({ fullText, fullReasoning, toolCall }) => { - this._setStreamState(threadId, { displayContentSoFar: fullText, reasoningSoFar: fullReasoning, toolCallSoFar: toolCall }, 'merge') + this._setStreamState(threadId, { isRunning: 'LLM', llmInfo: { displayContentSoFar: fullText, reasoningSoFar: fullReasoning, toolCallSoFar: toolCall ?? null }, interrupt: Promise.resolve(() => { if (llmCancelToken) this._llmMessageService.abort(llmCancelToken) }) }) }, onFinalMessage: async ({ fullText, fullReasoning, toolCall, anthropicReasoning, }) => { this._addMessageToThread(threadId, { role: 'assistant', displayContent: fullText, reasoning: fullReasoning, anthropicReasoning }) - this._setStreamState(threadId, { displayContentSoFar: undefined, reasoningSoFar: undefined, streamingToken: undefined, toolCallSoFar: undefined }, 'merge') + this._setStreamState(threadId, undefined) resMessageIsDonePromise(toolCall) // resolve with tool calls }, onError: async (error) => { - const messageSoFar = this.streamState[threadId]?.displayContentSoFar ?? '' - const reasoningSoFar = this.streamState[threadId]?.reasoningSoFar ?? '' + if (this.streamState[threadId]?.isRunning !== 'LLM') { + console.log('Unexpected onError when', this.streamState[threadId]?.isRunning) + return + } - this._setStreamState(threadId, { displayContentSoFar: undefined, reasoningSoFar: undefined, streamingToken: undefined, toolCallSoFar: undefined }, 'merge') if (nAttempts < CHAT_RETRIES) { nAttempts += 1 shouldRetry = true - await timeout(RETRY_DELAY) + this._setStreamState(threadId, undefined) // clear later so can be interrupted resMessageIsDonePromise() } else { - // const toolCallSoFar = this.streamState[threadId]?.toolCallSoFar // add assistant's message to chat history, and clear selection - this._addMessageToThread(threadId, { role: 'assistant', displayContent: messageSoFar, reasoning: reasoningSoFar, anthropicReasoning: null }) - this._setStreamState(threadId, { error }, 'set') + const { displayContentSoFar, reasoningSoFar, toolCallSoFar } = this.streamState[threadId].llmInfo + this._addMessageToThread(threadId, { role: 'assistant', displayContent: displayContentSoFar, reasoning: reasoningSoFar, anthropicReasoning: null }) + if (toolCallSoFar) this._addMessageToThread(threadId, { role: 'interrupted_streaming_tool', name: toolCallSoFar.name }) + this._setStreamState(threadId, { isRunning: undefined, error }) resMessageIsDonePromise() } }, onAbort: () => { // stop the loop to free up the promise, but don't modify state (already handled by whatever stopped it) aborted = true + this._setStreamState(threadId, undefined) resMessageIsDonePromise() this._metricsService.capture('Agent Loop Done (Aborted)', { nMessagesSent, chatMode }) }, }) - // should never happen, just for safety - if (llmCancelToken === null) { - this._setStreamState(threadId, { - error: { message: 'There was an unexpected error when sending your chat message.', fullError: null } - }, 'set') + // mark as streaming + if (!llmCancelToken) { + this._setStreamState(threadId, { isRunning: undefined, error: { message: 'There was an unexpected error when sending your chat message.', fullError: null } }) break } - this._setStreamState(threadId, { streamingToken: llmCancelToken }, 'merge') // new stream token for the new message - const toolCall = await messageIsDonePromise // wait for message to complete - this._setStreamState(threadId, { streamingToken: undefined }, 'merge') // streaming message is done - // this is a complete hack to make it so if an error loop was aborted, we stop (because onAbort does not get called if error happens instantly) - // maybe we should remove all the abort stuff and just make it so that we only go by state? - if (!this.streamState[threadId]?.isRunning) { return } + this._setStreamState(threadId, { isRunning: 'LLM', llmInfo: { displayContentSoFar: '', reasoningSoFar: '', toolCallSoFar: null }, interrupt: Promise.resolve(() => this._llmMessageService.abort(llmCancelToken)) }) + const toolCall = await messageIsDonePromise // wait for message to complete + // ending _setStreamStates are all handled above before resMessageIsDonePromise() if (aborted) { return } - if (shouldRetry) { continue } + if (shouldRetry) { + await timeout(RETRY_DELAY) + continue + } // call tool if there is one const tool: RawToolCallObj | undefined = toolCall - if (tool) { - const { awaitingUserApproval, interrupted } = await this._runToolCall(threadId, tool.name, tool.id, { preapproved: false, unvalidatedToolParams: tool.rawParams }) + if (!tool) continue // skip the next part if no tool - // stop if interrupted. we don't have to do this for llmMessage because we have a stream token for it and onAbort gets called, but we don't have the equivalent for tools. - // just detect tool interruption which is the same as chat interruption right now - if (!this.streamState[threadId]?.isRunning) { return } - if (aborted) { return } - if (interrupted) { return } + const { awaitingUserApproval, interrupted } = await this._runToolCall(threadId, tool.name, tool.id, { preapproved: false, unvalidatedToolParams: tool.rawParams }) - if (awaitingUserApproval) { - console.log('awaiting...') - isRunningWhenEnd = 'awaiting_user' - } - else { - shouldSendAnotherMessage = true - } - } + this._setStreamState(threadId, undefined) + + if (aborted) { return } + if (interrupted) { return } + + if (awaitingUserApproval) { isRunningWhenEnd = 'awaiting_user' } + else { shouldSendAnotherMessage = true } } // end while (attempts) } // end while (send message) // if awaiting user approval, keep isRunning true, else end isRunning - this._setStreamState(threadId, { isRunning: isRunningWhenEnd }, 'merge') + this._setStreamState(threadId, { isRunning: isRunningWhenEnd }) // add checkpoint before the next user message if (!isRunningWhenEnd) @@ -1036,7 +1071,7 @@ We only need to do it for files that were edited since `from`, ie files between } dismissStreamError(threadId: string): void { - this._setStreamState(threadId, { error: undefined }, 'merge') + this._setStreamState(threadId, undefined) } @@ -1044,13 +1079,11 @@ We only need to do it for files that were edited since `from`, ie files between const thread = this.state.allThreads[threadId] if (!thread) return // should never happen - const llmCancelToken = this.streamState[threadId]?.streamingToken // currently streaming LLM on this thread - if (llmCancelToken === undefined && this.streamState[threadId]?.isRunning) { - // if about to call the other LLM, just wait for and stop now - return + // interrupt existing stream + if (this.streamState[threadId]?.isRunning) { + console.log('stopping....') + await this.abortRunning(threadId) } - // stop it (this simply resolves the promise to free up space) - if (llmCancelToken !== undefined) this._llmMessageService.abort(llmCancelToken) // add dummy before this message to keep checkpoint before user message idea consistent if (thread.messages.length === 0) { @@ -1163,6 +1196,20 @@ We only need to do it for files that were edited since `from`, ie files between } + + getRelativeStr = (uri: URI) => { + const isInside = this._workspaceContextService.isInsideWorkspace(uri) + if (isInside) { + const f = this._workspaceContextService.getWorkspace().folders.find(f => uri.fsPath.startsWith(f.uri.fsPath)) + if (f) { return uri.fsPath.replace(f.uri.fsPath, '') } + else { return undefined } + } + else { + return undefined + } + } + + // gets the location of codespan link so the user can click on it generateCodespanLink: IChatThreadService['generateCodespanLink'] = async ({ codespanStr: _codespanStr, threadId }) => { @@ -1267,7 +1314,7 @@ We only need to do it for files that were edited since `from`, ie files between false, // searchOnlyEditableRange false, // isRegex true, // matchCase - ' ', // wordSeparators + null, //' ', // wordSeparators true // captureMatches ); diff --git a/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts b/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts index 7ed729ae..5ae17065 100644 --- a/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts +++ b/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts @@ -482,7 +482,7 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess }) const includeXMLToolDefinitions = !specialToolFormat - const runningTerminalIds = this.terminalToolService.listTerminalIds() + const runningTerminalIds = this.terminalToolService.listPersistentTerminalIds() const systemMessage = chat_systemMessage({ workspaceFolders, openedURIs, directoryStr, activeURI, runningTerminalIds, chatMode, includeXMLToolDefinitions }) return systemMessage } diff --git a/src/vs/workbench/contrib/void/browser/editCodeService.ts b/src/vs/workbench/contrib/void/browser/editCodeService.ts index b310c355..4cbce7ef 100644 --- a/src/vs/workbench/contrib/void/browser/editCodeService.ts +++ b/src/vs/workbench/contrib/void/browser/editCodeService.ts @@ -293,7 +293,7 @@ class EditCodeService extends Disposable implements IEditCodeService { // run: () => { this._commandService.executeCommand(VOID_OPEN_SETTINGS_ACTION_ID) } // }] // }, - // source: details ? `(Hold ${isMacintosh ? 'Option' : 'Alt'} to hover) - ${details}\n\nIf this persists, feel free to [report](https://github.com/voideditor/void/issues/new) it.` : undefined + // source: details ? `(Hold ${isMacintosh ? 'Option' : 'Alt'} to hover) - ${details}\n\nIf this persists, feel free to [report](https://github.com/voideditor-test/void/issues/new) it.` : undefined // }) // } diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx index 36ac3e53..c7e972b8 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx @@ -5,9 +5,6 @@ import React, { JSX, useMemo, useState } from 'react' import { marked, MarkedToken, Token } from 'marked' -import katex from 'katex' -import 'katex/dist/katex.min.css' -import dompurify from '../../../../../../../base/browser/dompurify/dompurify.js' import { convertToVscodeLang, detectLanguage } from '../../../../common/helpers/languageHelpers.js' import { BlockCodeApplyWrapper } from './ApplyBlockHoverButtons.js' @@ -17,6 +14,7 @@ import { URI } from '../../../../../../../base/common/uri.js' import { isAbsolute } from '../../../../../../../base/common/path.js' import { separateOutFirstLine } from '../../../../common/helpers/util.js' import { BlockCode } from '../util/inputs.js' +import { CodespanLocationLink } from '../../../../common/chatThreadServiceTypes.js' export type ChatMessageLocation = { @@ -36,59 +34,59 @@ function isValidUri(s: string): boolean { // renders contiguous string of latex eg $e^{i\pi}$ const LatexRender = ({ latex }: { latex: string }) => { + return {latex} + // try { + // let formula = latex; + // let displayMode = false; - try { - let formula = latex; - let displayMode = false; + // // Extract the formula from delimiters + // if (latex.startsWith('$') && latex.endsWith('$')) { + // // Check if it's display math $$...$$ + // if (latex.startsWith('$$') && latex.endsWith('$$')) { + // formula = latex.slice(2, -2); + // displayMode = true; + // } else { + // formula = latex.slice(1, -1); + // } + // } else if (latex.startsWith('\\(') && latex.endsWith('\\)')) { + // formula = latex.slice(2, -2); + // } else if (latex.startsWith('\\[') && latex.endsWith('\\]')) { + // formula = latex.slice(2, -2); + // displayMode = true; + // } - // Extract the formula from delimiters - if (latex.startsWith('$') && latex.endsWith('$')) { - // Check if it's display math $$...$$ - if (latex.startsWith('$$') && latex.endsWith('$$')) { - formula = latex.slice(2, -2); - displayMode = true; - } else { - formula = latex.slice(1, -1); - } - } else if (latex.startsWith('\\(') && latex.endsWith('\\)')) { - formula = latex.slice(2, -2); - } else if (latex.startsWith('\\[') && latex.endsWith('\\]')) { - formula = latex.slice(2, -2); - displayMode = true; - } + // // Render LaTeX + // const html = katex.renderToString(formula, { + // displayMode: displayMode, + // throwOnError: false, + // output: 'html' + // }); - // Render LaTeX - const html = katex.renderToString(formula, { - displayMode: displayMode, - throwOnError: false, - output: 'html' - }); + // // Sanitize the HTML output with DOMPurify + // const sanitizedHtml = dompurify.sanitize(html, { + // RETURN_TRUSTED_TYPE: true, + // USE_PROFILES: { html: true, svg: true, mathMl: true } + // }); - // Sanitize the HTML output with DOMPurify - const sanitizedHtml = dompurify.sanitize(html, { - RETURN_TRUSTED_TYPE: true, - USE_PROFILES: { html: true, svg: true, mathMl: true } - }); + // // Add proper styling based on mode + // const className = displayMode + // ? 'katex-block my-2 text-center' + // : 'katex-inline'; - // Add proper styling based on mode - const className = displayMode - ? 'katex-block my-2 text-center' - : 'katex-inline'; + // // Use the ref approach to avoid dangerouslySetInnerHTML + // const mathRef = React.useRef(null); - // Use the ref approach to avoid dangerouslySetInnerHTML - const mathRef = React.useRef(null); + // React.useEffect(() => { + // if (mathRef.current) { + // mathRef.current.innerHTML = sanitizedHtml as unknown as string; + // } + // }, [sanitizedHtml]); - React.useEffect(() => { - if (mathRef.current) { - mathRef.current.innerHTML = sanitizedHtml as unknown as string; - } - }, [sanitizedHtml]); - - return ; - } catch (error) { - console.error('KaTeX rendering error:', error); - return {latex}; - } + // return ; + // } catch (error) { + // console.error('KaTeX rendering error:', error); + // return {latex}; + // } } const Codespan = ({ text, className, onClick }: { text: string, className?: string, onClick?: () => void }) => { @@ -116,7 +114,7 @@ const CodespanWithLink = ({ text, rawText, chatMessageLocation }: { text: string const [didComputeCodespanLink, setDidComputeCodespanLink] = useState(false) - let link = undefined + let link: CodespanLocationLink | undefined = undefined if (rawText.endsWith('`')) { // if codespan was completed // get link from cache @@ -124,12 +122,12 @@ const CodespanWithLink = ({ text, rawText, chatMessageLocation }: { text: string if (link === undefined) { // if no link, generate link and add to cache - (chatThreadService.generateCodespanLink({ codespanStr: text, threadId }) + chatThreadService.generateCodespanLink({ codespanStr: text, threadId }) .then(link => { chatThreadService.addCodespanLink({ newLinkText: text, newLinkLocation: link, messageIdx, threadId }) setDidComputeCodespanLink(true) // rerender }) - ) + } } @@ -546,6 +544,7 @@ const RenderToken = ({ token, inPTag, codeURI, chatMessageLocation, tokenIdx, .. export const ChatMarkdownRender = ({ string, inPTag = false, chatMessageLocation, ...options }: { string: string, inPTag?: boolean, codeURI?: URI, chatMessageLocation: ChatMessageLocation | undefined } & RenderTokenOptions) => { + string = string.replaceAll('\nâ€Ē', '\n\nâ€Ē') const tokens = marked.lexer(string); // https://marked.js.org/using_pro#renderer return ( <> diff --git a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx index 2a531815..191b7212 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/quick-edit-tsx/QuickEditChat.tsx @@ -12,6 +12,9 @@ import { VOID_CTRL_K_ACTION_ID } from '../../../actionIDs.js'; import { useRefState } from '../util/helpers.js'; import { isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js'; + + + export const QuickEditChat = ({ diffareaid, onChangeHeight, diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 70e4000e..a60a21ee 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -30,6 +30,7 @@ import { MAX_FILE_CHARS_PAGE, MAX_TERMINAL_INACTIVE_TIME, ToolName, toolNames } import { RawToolCallObj } from '../../../../common/sendLLMMessageTypes.js'; import ErrorBoundary from './ErrorBoundary.js'; import { ToolApprovalTypeSwitch } from '../void-settings-tsx/Settings.js'; +import { persistentTerminalNameOfId } from '../../../terminalToolService.js'; @@ -351,7 +352,7 @@ export const VoidChatArea: React.FC = ({
-
+
{featureName === 'Chat' && }
@@ -464,19 +465,10 @@ const ScrollToBottomContainer = ({ children, className, style, scrollContainerRe ); }; -const getRelative = (uri: URI, accessor: ReturnType) => { - const workspaceContextService = accessor.get('IWorkspaceContextService') - let path: string - const isInside = workspaceContextService.isInsideWorkspace(uri) - if (isInside) { - const f = workspaceContextService.getWorkspace().folders.find(f => uri.fsPath.startsWith(f.uri.fsPath)) - if (f) { path = uri.fsPath.replace(f.uri.fsPath, '') } - else { path = uri.fsPath } - } - else { - path = uri.fsPath - } - return path || undefined + +export const getRelative = (uri: URI, accessor: ReturnType) => { + const chatThreadService = accessor.get('IChatThreadService') + return chatThreadService.getRelativeStr(uri) || uri.fsPath } export const getFolderName = (pathStr: string) => { @@ -683,6 +675,7 @@ type ToolHeaderParams = { children?: React.ReactNode; bottomChildren?: React.ReactNode; onClick?: () => void; + desc2OnClick?: () => void; isOpen?: boolean; className?: string; } @@ -700,6 +693,7 @@ const ToolHeaderWrapper = ({ bottomChildren, isError, onClick, + desc2OnClick, isOpen, isRejected, className, // applies to the main content @@ -769,7 +763,7 @@ const ToolHeaderWrapper = ({ data-tooltip-content={'Canceled'} data-tooltip-place='top' />} - {desc2 && + {desc2 && {desc2} } {numResults !== undefined && ( @@ -925,7 +919,7 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhost, curr // cancel any streams on this thread const threadId = chatThreadsService.state.currentThreadId - chatThreadsService.stopRunning(threadId) + await chatThreadsService.abortRunning(threadId) // update state setIsBeingEdited(false) @@ -942,9 +936,9 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhost, curr requestAnimationFrame(() => _scrollToBottom?.()) } - const onAbort = () => { + const onAbort = async () => { const threadId = chatThreadsService.state.currentThreadId - chatThreadsService.stopRunning(threadId) + await chatThreadsService.abortRunning(threadId) } const onKeyDown = (e: KeyboardEvent) => { @@ -1231,9 +1225,13 @@ const titleOfToolName = { 'create_file_or_folder': { done: `Created`, proposed: `Create`, running: loadingTitleWrapper(`Creating`) }, 'delete_file_or_folder': { done: `Deleted`, proposed: `Delete`, running: loadingTitleWrapper(`Deleting`) }, 'edit_file': { done: `Edited file`, proposed: 'Edit file', running: loadingTitleWrapper('Editing file') }, + 'run_command': { done: `Ran terminal`, proposed: 'Run terminal', running: loadingTitleWrapper('Running terminal') }, + 'run_persistent_command': { done: `Ran terminal`, proposed: 'Run terminal', running: loadingTitleWrapper('Running terminal') }, + 'open_persistent_terminal': { done: `Opened terminal`, proposed: 'Open terminal', running: loadingTitleWrapper('Opening terminal') }, 'kill_persistent_terminal': { done: `Killed terminal`, proposed: 'Kill terminal', running: loadingTitleWrapper('Killing terminal') }, + 'read_lint_errors': { done: `Read lint errors`, proposed: 'Read lint errors', running: loadingTitleWrapper('Reading lint errors') }, 'search_in_file': { done: 'Searched in file', proposed: 'Search in file', running: loadingTitleWrapper('Searching in file') }, } as const satisfies Record @@ -1289,7 +1287,6 @@ const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName const toolParams = _toolParams as ToolCallParams['search_in_file']; return { desc1: `"${toolParams.query}"`, - desc1Info: getRelative(toolParams.uri, accessor), }; }, 'create_file_or_folder': () => { @@ -1317,7 +1314,12 @@ const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName const toolParams = _toolParams as ToolCallParams['run_command'] return { desc1: `"${toolParams.command}"`, - desc1Info: toolParams.bgTerminalId + } + }, + 'run_persistent_command': () => { + const toolParams = _toolParams as ToolCallParams['run_persistent_command'] + return { + desc1: `"${toolParams.command}"`, } }, 'open_persistent_terminal': () => { @@ -1326,7 +1328,7 @@ const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName }, 'kill_persistent_terminal': () => { const toolParams = _toolParams as ToolCallParams['kill_persistent_terminal'] - return { desc1: toolParams.terminalId } + return { desc1: toolParams.persistentTerminalId } }, 'get_dir_tree': () => { const toolParams = _toolParams as ToolCallParams['get_dir_tree'] @@ -1537,6 +1539,105 @@ const CanceledTool = ({ toolName }: { toolName: ToolName }) => { } + +const CommandTool = ({ toolMessage, type, threadId }: { threadId: string } & ({ + toolMessage: Exclude, { type: 'invalid_params' }> + type: 'run_command' +} | { + toolMessage: Exclude, { type: 'invalid_params' }> + type: | 'run_persistent_command' +})) => { + const accessor = useAccessor() + + const commandService = accessor.get('ICommandService') + const terminalToolsService = accessor.get('ITerminalToolService') + const toolsService = accessor.get('IToolsService') + const terminalService = accessor.get('ITerminalService') + const isError = toolMessage.type === 'tool_error' + const title = getTitle(toolMessage) + const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) + const icon = null + const streamState = useChatThreadsStreamState(threadId) + + const divRef = useRef(null) + + const isRejected = toolMessage.type === 'rejected' + const { rawParams, params } = toolMessage + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } + + + const effect = async () => { + if (streamState?.isRunning !== 'tool') return + if (type !== 'run_command' || toolMessage.type !== 'running_now') return; + + // wait for the interruptor so we know it's running + + await streamState?.interrupt + const container = divRef.current; + if (!container) return; + + const terminal = terminalToolsService.getTemporaryTerminal(toolMessage.params.terminalId); + if (!terminal) return; + + terminal.detachFromElement(); + terminal.attachToElement(container); + + // Listen for size changes + const resizeObserver = new ResizeObserver((entries) => { + const height = entries[0].borderBoxSize[0].blockSize + const width = entries[0].borderBoxSize[0].inlineSize + // Layout terminal to fit container dimensions + if (typeof terminal.layout === 'function') { + terminalService.setActiveInstance(terminal) + terminal.attachToElement(container); + terminal.layout({ width, height }); + + } + }) + + resizeObserver.observe(container); + return () => { terminal.detachFromElement(); resizeObserver?.disconnect(); } + } + + useEffect(() => { + effect() + }, [terminalToolsService, toolMessage, toolMessage.type, type]); + + if (toolMessage.type === 'success') { + const { result } = toolMessage + + // it's unclear that this is a button and not an icon. + // componentParams.desc2 = { terminalToolsService.openTerminal(terminalId) }} + // /> + + let msg: string + if (type === 'run_command') msg = toolsService.stringOfResult['run_command'](toolMessage.params, result) + else msg = toolsService.stringOfResult['run_persistent_command'](toolMessage.params, result) + + componentParams.children = +
+ +
+
+ } + else if (toolMessage.type === 'tool_error') { + const { result } = toolMessage + componentParams.children = + {result} + + } + else if (toolMessage.type === 'running_now') { + componentParams.children =
+ } + else if (toolMessage.type === 'rejected' || toolMessage.type === 'tool_request') { + } + + return <> + + +} + type ResultWrapper = (props: { toolMessage: Exclude, { type: 'invalid_params' }>, messageIdx: number, threadId: string }) => React.ReactNode const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, } } = { 'read_file': { @@ -1549,13 +1650,13 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor); const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } if (toolMessage.params.startLine !== null || toolMessage.params.endLine !== null) { const start = toolMessage.params.startLine === null ? `1` : `${toolMessage.params.startLine}` @@ -1594,13 +1695,13 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } if (params.uri) { const rel = getRelative(params.uri, accessor) @@ -1642,13 +1743,13 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } if (params.uri) { const rel = getRelative(params.uri, accessor) @@ -1692,16 +1793,16 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const accessor = useAccessor() const commandService = accessor.get('ICommandService') const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const title = getTitle(toolMessage) const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } if (params.includePattern) { componentParams.info = `Only search in ${params.includePattern}` @@ -1741,16 +1842,16 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const accessor = useAccessor() const commandService = accessor.get('ICommandService') const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const title = getTitle(toolMessage) const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } if (params.searchInFolder || params.isRegex) { let info: string[] = [] @@ -1758,9 +1859,7 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const rel = getRelative(params.searchInFolder, accessor) if (rel) info.push(`Only search in ${rel}`) } - if (params.isRegex) { - info.push(`Treat as regex`) - } + if (params.isRegex) { info.push(`Treat search as regex`) } componentParams.info = info.join('; ') } @@ -1798,15 +1897,22 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const accessor = useAccessor(); const toolsService = accessor.get('IToolsService'); const title = getTitle(toolMessage); + const isError = toolMessage.type === 'tool_error'; + const isRejected = toolMessage.type === 'rejected' const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor); const icon = null; - if (toolMessage.type === 'tool_request' || toolMessage.type === 'rejected' || toolMessage.type === 'running_now') return null; + if (toolMessage.type === 'tool_request') return null // do not show past requests + if (toolMessage.type === 'running_now') return null // do not show running - const isError = toolMessage.type === 'tool_error'; const { rawParams, params } = toolMessage; - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon }; - if (params.isRegex) componentParams.info = 'Treat as regex' + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected }; + + const infoarr: string[] = [] + const uriStr = getRelative(params.uri, accessor) + if (uriStr) infoarr.push(uriStr) + if (params.isRegex) infoarr.push('Treat search as regex') + componentParams.info = infoarr.join('; ') if (toolMessage.type === 'success') { const { result } = toolMessage; // result is array of snippets @@ -1844,13 +1950,13 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } componentParams.info = getRelative(uri, accessor) // full path @@ -2049,68 +2155,16 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, // --- 'run_command': { - resultWrapper: ({ toolMessage }) => { - const accessor = useAccessor() - const commandService = accessor.get('ICommandService') - const terminalToolsService = accessor.get('ITerminalToolService') - const isError = toolMessage.type === 'tool_error' - const title = getTitle(toolMessage) - const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) - const icon = null - - const isRejected = toolMessage.type === 'rejected' - const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } - - if (toolMessage.type === 'success') { - const { result } = toolMessage - const { command } = params - const { resolveReason, result: terminalResult } = result - - // it's unclear that this is a button and not an icon. - // componentParams.desc2 = { terminalToolsService.openTerminal(terminalId) }} - // /> - - const additionalDetailsStr = resolveReason.type === 'done' ? (resolveReason.exitCode !== 0 ? `\nError: exit code ${resolveReason.exitCode}` : null) - : resolveReason.type === 'timeout' ? `\n(timed out)` - : null - - componentParams.children = -
-
- {`Ran command: `} - {command} -
- {(terminalResult + additionalDetailsStr).length &&
- {`Result: `} - {terminalResult} - {additionalDetailsStr} -
} -
-
- - if (params.bgTerminalId) - componentParams.desc2 = `(terminal ${params.bgTerminalId})` - - } - else if (toolMessage.type === 'rejected' || toolMessage.type === 'tool_error' || toolMessage.type === 'running_now' || toolMessage.type === 'tool_request') { - const { bgTerminalId, command } = params - if (bgTerminalId) { - componentParams.desc2 = '(persistent terminal)' - if (terminalToolsService.terminalExists(bgTerminalId)) - componentParams.onClick = () => terminalToolsService.focusTerminal(bgTerminalId) - } - if (toolMessage.type === 'tool_error') { - const { result } = toolMessage - componentParams.children = {result} - } - } - - return + resultWrapper: (params) => { + return } }, + 'run_persistent_command': { + resultWrapper: (params) => { + return + } + }, 'open_persistent_terminal': { resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() @@ -2120,22 +2174,20 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const title = getTitle(toolMessage) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } + componentParams.info = params.cwd ? `Running in ${getRelative(URI.file(params.cwd), accessor)}` : '' if (toolMessage.type === 'success') { const { result } = toolMessage - const { terminalId } = result - if (terminalId) { - componentParams.desc2 = `(terminal ${terminalId})` - if (terminalToolsService.terminalExists(terminalId)) - componentParams.onClick = () => terminalToolsService.focusTerminal(terminalId) - } + const { persistentTerminalId } = result + componentParams.desc1 = persistentTerminalNameOfId(persistentTerminalId) + componentParams.onClick = () => terminalToolsService.focusPersistentTerminal(persistentTerminalId) } else if (toolMessage.type === 'tool_error') { const { result } = toolMessage @@ -2153,21 +2205,24 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') + const terminalToolsService = accessor.get('ITerminalToolService') const { desc1, desc1Info } = toolNameToDesc(toolMessage.name, toolMessage.params, accessor) const title = getTitle(toolMessage) const icon = null - if (toolMessage.type === 'tool_request') return null - if (toolMessage.type === 'rejected') return null // will never happen, not rejectable + if (toolMessage.type === 'tool_request') return null // do not show past requests if (toolMessage.type === 'running_now') return null // do not show running const isError = toolMessage.type === 'tool_error' + const isRejected = toolMessage.type === 'rejected' const { rawParams, params } = toolMessage - const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, } + const componentParams: ToolHeaderParams = { title, desc1, desc1Info, isError, icon, isRejected, } if (toolMessage.type === 'success') { - const { result } = toolMessage + const { persistentTerminalId } = params + componentParams.desc1 = persistentTerminalNameOfId(persistentTerminalId) + componentParams.onClick = () => terminalToolsService.focusPersistentTerminal(persistentTerminalId) } else if (toolMessage.type === 'tool_error') { const { result } = toolMessage @@ -2686,9 +2741,7 @@ export const SidebarChat = () => { const currThreadStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId) const isRunning = currThreadStreamState?.isRunning const latestError = currThreadStreamState?.error - const displayContentSoFar = currThreadStreamState?.displayContentSoFar - const toolCallSoFar = currThreadStreamState?.toolCallSoFar - const reasoningSoFar = currThreadStreamState?.reasoningSoFar + const { displayContentSoFar, toolCallSoFar, reasoningSoFar } = currThreadStreamState?.llmInfo ?? {} // this is just if it's currently being generated, NOT if it's currently running const toolIsGenerating = toolCallSoFar && !toolCallSoFar.isDone && toolCallSoFar.name === 'edit_file' // show loading for slow tools (right now just edit) @@ -2726,9 +2779,9 @@ export const SidebarChat = () => { }, [chatThreadsService, isDisabled, isRunning, textAreaRef, textAreaFnsRef, setSelections, settingsState]) - const onAbort = () => { + const onAbort = async () => { const threadId = currentThread.id - chatThreadsService.stopRunning(threadId) + await chatThreadsService.abortRunning(threadId) } const keybindingString = accessor.get('IKeybindingService').lookupKeybinding(VOID_CTRL_L_ACTION_ID)?.getLabel() diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx index 91281214..69132cfd 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/inputs.tsx @@ -467,7 +467,7 @@ export const VoidInputBox2 = forwardRef(fun rows={1} placeholder={placeholder} /> -
{`idx ${optionIdx}`}
+ {/*
{`idx ${optionIdx}`}
*/} {isMenuOpen && (
{ colorThemeState = themeService.getColorTheme().type disposables.push( - themeService.onDidColorThemeChange(({ theme }) => { - colorThemeState = theme.type + themeService.onDidColorThemeChange(({ type }) => { + colorThemeState = type colorThemeStateListeners.forEach(l => l(colorThemeState)) }) ) @@ -219,6 +220,7 @@ const getReactAccessor = (accessor: ServicesAccessor) => { INativeHostService: accessor.get(INativeHostService), IToolsService: accessor.get(IToolsService), IConvertToLLMMessageService: accessor.get(IConvertToLLMMessageService), + ITerminalService: accessor.get(ITerminalService), } as const return reactAccessor diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx index 87eafad0..1a3189a3 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx @@ -553,7 +553,7 @@ const VoidOnboardingContent = () => { // can be md const detailedDescOfWantToUseOption: { [wantToUseOption in WantToUseOption]: string } = { smart: "Most intelligent and best for agent mode.", - private: "Private-hosted so your data never leaves your computer or network. [Email us](mailto:founders@voideditor.com) for help setting up at your company.", + private: "Private-hosted so your data never leaves your computer or network. [Email us](mailto:founders@voideditor-test.com) for help setting up at your company.", cheap: "Use great deals like Gemini 2.5 Pro, or self-host a model with Ollama or vLLM for free.", all: "", } diff --git a/src/vs/workbench/contrib/void/browser/terminalToolService.ts b/src/vs/workbench/contrib/void/browser/terminalToolService.ts index 7abc98d6..a52e1516 100644 --- a/src/vs/workbench/contrib/void/browser/terminalToolService.ts +++ b/src/vs/workbench/contrib/void/browser/terminalToolService.ts @@ -5,11 +5,13 @@ import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { removeAnsiEscapeCodes } from '../../../../base/common/strings.js'; +import { URI } from '../../../../base/common/uri.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; -import { TerminalExitReason, TerminalLocation } from '../../../../platform/terminal/common/terminal.js'; -import { ITerminalService, ITerminalInstance } from '../../../../workbench/contrib/terminal/browser/terminal.js'; -import { MAX_TERMINAL_CHARS, MAX_TERMINAL_INACTIVE_TIME } from '../common/prompt/prompts.js'; +import { TerminalLocation } from '../../../../platform/terminal/common/terminal.js'; +import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; +import { ITerminalService, ITerminalInstance, ICreateTerminalOptions } from '../../../../workbench/contrib/terminal/browser/terminal.js'; +import { MAX_TERMINAL_BG_COMMAND_TIME, MAX_TERMINAL_CHARS, MAX_TERMINAL_INACTIVE_TIME } from '../common/prompt/prompts.js'; import { TerminalResolveReason } from '../common/toolsServiceTypes.js'; @@ -17,13 +19,16 @@ import { TerminalResolveReason } from '../common/toolsServiceTypes.js'; export interface ITerminalToolService { readonly _serviceBrand: undefined; - listTerminalIds(): string[]; - runCommand(command: string, bgTerminalId: string | null): Promise<{ terminalId: string, resPromise: Promise<{ result: string, resolveReason: TerminalResolveReason }> }>; - focusTerminal(terminalId: string): Promise - terminalExists(terminalId: string): boolean + listPersistentTerminalIds(): string[]; + runCommand(command: string, opts: { type: 'persistent', persistentTerminalId: string } | { type: 'ephemeral', cwd: string | null, terminalId: string }): Promise<{ interrupt: () => void; resPromise: Promise<{ result: string, resolveReason: TerminalResolveReason }> }>; + focusPersistentTerminal(terminalId: string): Promise + persistentTerminalExists(terminalId: string): boolean - createTerminal(): Promise - killTerminal(terminalId: string): Promise + createPersistentTerminal(opts: { cwd: string | null }): Promise + killPersistentTerminal(terminalId: string): Promise + + getPersistentTerminal(terminalId: string): ITerminalInstance | undefined + getTemporaryTerminal(terminalId: string): ITerminalInstance | undefined } export const ITerminalToolService = createDecorator('TerminalToolService'); @@ -39,11 +44,11 @@ function isCommandComplete(output: string) { } -const nameOfId = (id: string) => { +export const persistentTerminalNameOfId = (id: string) => { if (id === '1') return 'Void Agent' return `Void Agent (${id})` } -const idOfName = (name: string) => { +export const idOfPersistentTerminalName = (name: string) => { if (name === 'Void Agent') return '1' const match = name.match(/Void Agent \((\d+)\)/) @@ -55,10 +60,12 @@ const idOfName = (name: string) => { export class TerminalToolService extends Disposable implements ITerminalToolService { readonly _serviceBrand: undefined; - private terminalInstanceOfId: Record = {} + private persistentTerminalInstanceOfId: Record = {} + private temporaryTerminalInstanceOfId: Record = {} constructor( @ITerminalService private readonly terminalService: ITerminalService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, ) { super(); @@ -66,8 +73,8 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ const initializeTerminal = (terminal: ITerminalInstance) => { // when exit, remove const d = terminal.onExit(() => { - const terminalId = idOfName(terminal.title) - if (terminalId !== null && (terminalId in this.terminalInstanceOfId)) delete this.terminalInstanceOfId[terminalId] + const terminalId = idOfPersistentTerminalName(terminal.title) + if (terminalId !== null && (terminalId in this.persistentTerminalInstanceOfId)) delete this.persistentTerminalInstanceOfId[terminalId] d.dispose() }) } @@ -75,8 +82,8 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ // initialize any terminals that are already open for (const terminal of terminalService.instances) { - const proposedTerminalId = idOfName(terminal.title) - if (proposedTerminalId) this.terminalInstanceOfId[proposedTerminalId] = terminal + const proposedTerminalId = idOfPersistentTerminalName(terminal.title) + if (proposedTerminalId) this.persistentTerminalInstanceOfId[proposedTerminalId] = terminal initializeTerminal(terminal) } @@ -88,32 +95,36 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ } - listTerminalIds() { - return Object.keys(this.terminalInstanceOfId) + listPersistentTerminalIds() { + return Object.keys(this.persistentTerminalInstanceOfId) } getValidNewTerminalId(): string { // {1 2 3} # size 3, new=4 // {1 3 4} # size 3, new=2 // 1 <= newTerminalId <= n + 1 - const n = Object.keys(this.terminalInstanceOfId).length; + const n = Object.keys(this.persistentTerminalInstanceOfId).length; if (n === 0) return '1' for (let i = 1; i <= n + 1; i++) { const potentialId = i + ''; - if (!(potentialId in this.terminalInstanceOfId)) return potentialId; + if (!(potentialId in this.persistentTerminalInstanceOfId)) return potentialId; } throw new Error('This should never be reached by pigeonhole principle'); } - async createTerminal() { - // create new terminal and return its ID - const terminalId = this.getValidNewTerminalId(); - const terminal = await this.terminalService.createTerminal({ - location: TerminalLocation.Panel, - config: { name: nameOfId(terminalId), title: nameOfId(terminalId) }, - }) + private async _createTerminal(props: { cwd: string | null, config: ICreateTerminalOptions['config'] }) { + const { cwd: override_cwd, config } = props + + const cwd: URI | string | undefined = (override_cwd ?? undefined) ?? this.workspaceContextService.getWorkspace().folders[0]?.uri + + // create new terminal and return its ID + const terminal = await this.terminalService.createTerminal({ + cwd: cwd, + location: TerminalLocation.Panel, + config: config, + }) // when a new terminal is created, there is an initial command that gets run which is empty, wait for it to end before returning const disposables: IDisposable[] = [] @@ -130,26 +141,49 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ await Promise.any([waitForMount, waitForTimeout,]) disposables.forEach(d => d.dispose()) - this.terminalInstanceOfId[terminalId] = terminal + return terminal + + } + + createPersistentTerminal: ITerminalToolService['createPersistentTerminal'] = async ({ cwd }) => { + const terminalId = this.getValidNewTerminalId(); + const config = { name: persistentTerminalNameOfId(terminalId), title: persistentTerminalNameOfId(terminalId) } + const terminal = await this._createTerminal({ cwd, config, }) + this.persistentTerminalInstanceOfId[terminalId] = terminal return terminalId } - async killTerminal(terminalId: string) { - const terminal = this.terminalInstanceOfId[terminalId] + async killPersistentTerminal(terminalId: string) { + const terminal = this.persistentTerminalInstanceOfId[terminalId] if (!terminal) throw new Error(`Kill Terminal: Terminal with ID ${terminalId} did not exist.`); - terminal.dispose(TerminalExitReason.Extension) - delete this.terminalInstanceOfId[terminalId] + terminal.dispose() + delete this.persistentTerminalInstanceOfId[terminalId] return } - terminalExists(terminalId: string): boolean { - return terminalId in this.terminalInstanceOfId + persistentTerminalExists(terminalId: string): boolean { + return terminalId in this.persistentTerminalInstanceOfId } - focusTerminal: ITerminalToolService['focusTerminal'] = async (terminalId) => { + getTemporaryTerminal(terminalId: string): ITerminalInstance | undefined { if (!terminalId) return - const terminal = this.terminalInstanceOfId[terminalId] + const terminal = this.temporaryTerminalInstanceOfId[terminalId] + if (!terminal) return // should never happen + return terminal + } + + getPersistentTerminal(terminalId: string): ITerminalInstance | undefined { + if (!terminalId) return + const terminal = this.persistentTerminalInstanceOfId[terminalId] + if (!terminal) return // should never happen + return terminal + } + + + focusPersistentTerminal: ITerminalToolService['focusPersistentTerminal'] = async (terminalId) => { + if (!terminalId) return + const terminal = this.persistentTerminalInstanceOfId[terminalId] if (!terminal) return // should never happen this.terminalService.setActiveInstance(terminal) await this.terminalService.focusActiveInstance() @@ -158,30 +192,38 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ - runCommand: ITerminalToolService['runCommand'] = async (command, bgTerminalId) => { + runCommand: ITerminalToolService['runCommand'] = async (command, params) => { + const { type } = params await this.terminalService.whenConnected; let terminal: ITerminalInstance const disposables: IDisposable[] = [] - const isBG = bgTerminalId !== null - let terminalId: string - if (isBG) { // BG process - terminal = this.terminalInstanceOfId[bgTerminalId]; - if (!terminal) throw new Error(`Unexpected internal error: Terminal with ID ${bgTerminalId} did not exist.`); - terminalId = bgTerminalId + const isPersistent = type === 'persistent' + + if (isPersistent) { // BG process + const { persistentTerminalId } = params + terminal = this.persistentTerminalInstanceOfId[persistentTerminalId]; + if (!terminal) throw new Error(`Unexpected internal error: Terminal with ID ${persistentTerminalId} did not exist.`); } else { - terminalId = await this.createTerminal() - terminal = this.terminalInstanceOfId[terminalId] - if (!terminal) throw new Error(`Unexpected error: Terminal could not be created.`) + const { cwd } = params + terminal = await this._createTerminal({ cwd: cwd, config: { name: 'Void Temporary Terminal', title: 'Void Temporary Terminal' } }) + this.temporaryTerminalInstanceOfId[params.terminalId] = terminal } + const interrupt = () => { + terminal.dispose() + if (!isPersistent) + delete this.temporaryTerminalInstanceOfId[params.terminalId] + } const waitForResult = async () => { - // focus the terminal about to run - this.terminalService.setActiveInstance(terminal) - await this.terminalService.focusActiveInstance() + if (isPersistent) { + // focus the terminal about to run + this.terminalService.setActiveInstance(terminal) + await this.terminalService.focusActiveInstance() + } let result: string = '' let resolveReason: TerminalResolveReason | undefined = undefined @@ -207,30 +249,38 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ // send the command here await terminal.sendText(command, true) - // inactivity-based timeout - const waitUntilInactive = new Promise(res => { - let globalTimeoutId: ReturnType; - const resetTimer = () => { - clearTimeout(globalTimeoutId); - globalTimeoutId = setTimeout(() => { - if (resolveReason) return - + const waitUntilInterrupt = isPersistent ? + // timeout after X seconds + new Promise((res) => { + setTimeout(() => { resolveReason = { type: 'timeout' }; - res(); - }, MAX_TERMINAL_INACTIVE_TIME * 1000); - }; + res() + }, MAX_TERMINAL_BG_COMMAND_TIME * 1000) + }) + // inactivity-based timeout + : new Promise(res => { + let globalTimeoutId: ReturnType; + const resetTimer = () => { + clearTimeout(globalTimeoutId); + globalTimeoutId = setTimeout(() => { + if (resolveReason) return - const dTimeout = terminal.onData(() => { resetTimer(); }); - disposables.push(dTimeout, toDisposable(() => clearTimeout(globalTimeoutId))); - resetTimer(); - }); + resolveReason = { type: 'timeout' }; + res(); + }, MAX_TERMINAL_INACTIVE_TIME * 1000); + }; + + const dTimeout = terminal.onData(() => { resetTimer(); }); + disposables.push(dTimeout, toDisposable(() => clearTimeout(globalTimeoutId))); + resetTimer(); + }) // wait for result - await Promise.any([waitUntilDone, waitUntilInactive,]) + await Promise.any([waitUntilDone, waitUntilInterrupt]) disposables.forEach(d => d.dispose()) - if (!isBG) { - await this.killTerminal(terminalId) + if (!isPersistent) { + interrupt() } if (!resolveReason) throw new Error('Unexpected internal error: Promise.any should have resolved with a reason.') @@ -251,7 +301,10 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ } const resPromise = waitForResult() - return { terminalId, resPromise } + return { + interrupt, + resPromise, + } } diff --git a/src/vs/workbench/contrib/void/browser/toolsService.ts b/src/vs/workbench/contrib/void/browser/toolsService.ts index bdacb18e..da5e7005 100644 --- a/src/vs/workbench/contrib/void/browser/toolsService.ts +++ b/src/vs/workbench/contrib/void/browser/toolsService.ts @@ -17,8 +17,9 @@ import { computeDirectoryTree1Deep, IDirectoryStrService, stringifyDirectoryTree import { IMarkerService, MarkerSeverity } from '../../../../platform/markers/common/markers.js' import { timeout } from '../../../../base/common/async.js' import { RawToolParamsObj } from '../common/sendLLMMessageTypes.js' -import { MAX_CHILDREN_URIs_PAGE, MAX_FILE_CHARS_PAGE, MAX_TERMINAL_INACTIVE_TIME, ToolName } from '../common/prompt/prompts.js' +import { MAX_CHILDREN_URIs_PAGE, MAX_FILE_CHARS_PAGE, MAX_TERMINAL_BG_COMMAND_TIME, MAX_TERMINAL_INACTIVE_TIME, ToolName } from '../common/prompt/prompts.js' import { IVoidSettingsService } from '../common/voidSettingsService.js' +import { generateUuid } from '../../../../base/common/uuid.js' // tool use for AI @@ -83,16 +84,8 @@ const validateNumber = (numStr: unknown, opts: { default: number | null }) => { return opts.default } -const validateRecursiveParamStr = (paramsUnknown: unknown) => { - if (!paramsUnknown) return false - if (typeof paramsUnknown !== 'string') throw new Error('Invalid LLM output format: Error calling tool: provided params must be a string.') - const params = paramsUnknown - const isRecursive = params.includes('r') - return isRecursive -} - const validateProposedTerminalId = (terminalIdUnknown: unknown) => { - if (!terminalIdUnknown) return '1' + if (!terminalIdUnknown) throw new Error(`A value for terminalID must be specified, but the value was "${terminalIdUnknown}"`) const terminalId = terminalIdUnknown + '' return terminalId } @@ -233,9 +226,9 @@ export class ToolsService implements IToolsService { }, delete_file_or_folder: (params: RawToolParamsObj) => { - const { uri: uriUnknown, params: paramsStr } = params + const { uri: uriUnknown, is_recursive: isRecursiveUnknown } = params const uri = validateURI(uriUnknown) - const isRecursive = validateRecursiveParamStr(paramsStr) + const isRecursive = validateBoolean(isRecursiveUnknown, { default: false }) const uriStr = validateStr('uri', uriUnknown) const isFolder = checkIfIsFolder(uriStr) return { uri, isRecursive, isFolder } @@ -251,19 +244,28 @@ export class ToolsService implements IToolsService { // --- run_command: (params: RawToolParamsObj) => { - const { command: commandUnknown, terminal_id: terminalIdUnknown } = params; - const command = validateStr('command', commandUnknown); - const proposedTerminalId = terminalIdUnknown ? validateProposedTerminalId(terminalIdUnknown) : null; - return { command, bgTerminalId: proposedTerminalId }; + const { command: commandUnknown, cwd: cwdUnknown } = params + const command = validateStr('command', commandUnknown) + const cwd = validateOptionalStr('cwd', cwdUnknown) + const terminalId = generateUuid() + return { command, cwd, terminalId } }, - open_persistent_terminal: (_params: RawToolParamsObj) => { + run_persistent_command: (params: RawToolParamsObj) => { + const { command: commandUnknown, persistent_terminal_id: persistentTerminalIdUnknown } = params; + const command = validateStr('command', commandUnknown); + const persistentTerminalId = validateProposedTerminalId(persistentTerminalIdUnknown) + return { command, persistentTerminalId }; + }, + open_persistent_terminal: (params: RawToolParamsObj) => { + const { cwd: cwdUnknown } = params; + const cwd = validateOptionalStr('cwd', cwdUnknown) // No parameters needed; will open a new background terminal - return {}; + return { cwd }; }, kill_persistent_terminal: (params: RawToolParamsObj) => { - const { terminal_id: terminalIdUnknown } = params; - const terminalId = validateProposedTerminalId(terminalIdUnknown); - return { terminalId }; + const { persistent_terminal_id: terminalIdUnknown } = params; + const persistentTerminalId = validateProposedTerminalId(terminalIdUnknown); + return { persistentTerminalId }; }, } @@ -414,21 +416,23 @@ export class ToolsService implements IToolsService { return { result: lintErrorsPromise, interruptTool } }, // --- - run_command: async ({ command, bgTerminalId }) => { - const { terminalId, resPromise } = await this.terminalToolService.runCommand(command, bgTerminalId) - const interruptTool = () => { - this.terminalToolService.killTerminal(terminalId) - } - return { result: resPromise, interruptTool } + run_command: async ({ command, cwd, terminalId }) => { + const { resPromise, interrupt } = await this.terminalToolService.runCommand(command, { type: 'ephemeral', cwd, terminalId }) + console.log('qqq', interrupt) + return { result: resPromise, interruptTool: interrupt } }, - open_persistent_terminal: async () => { - // Open a new background terminal without waiting for completion - const terminalId = await this.terminalToolService.createTerminal() - return { result: { terminalId } } + run_persistent_command: async ({ command, persistentTerminalId }) => { + const { resPromise, interrupt } = await this.terminalToolService.runCommand(command, { type: 'persistent', persistentTerminalId }) + console.log('qqq', interrupt) + return { result: resPromise, interruptTool: interrupt } }, - kill_persistent_terminal: async ({ terminalId }) => { + open_persistent_terminal: async ({ cwd }) => { + const persistentTerminalId = await this.terminalToolService.createPersistentTerminal({ cwd }) + return { result: { persistentTerminalId } } + }, + kill_persistent_terminal: async ({ persistentTerminalId }) => { // Close the background terminal by sending exit - await this.terminalToolService.killTerminal(terminalId) + await this.terminalToolService.killPersistentTerminal(persistentTerminalId) return { result: {} } }, @@ -493,39 +497,38 @@ export class ToolsService implements IToolsService { return `Change successfully made to ${params.uri.fsPath}.${lintErrsString}` }, run_command: (params, result) => { - const { - resolveReason, - result: result_, - } = result - const { bgTerminalId } = params - + const { resolveReason, result: result_, } = result // success if (resolveReason.type === 'done') { - const desc = bgTerminalId ? ` in terminal ${bgTerminalId}` : '' - return `Terminal command executed and finished${desc}. Result (exit code ${resolveReason.exitCode}):\n${result_}` - } - - // bg command - if (bgTerminalId !== null) { - if (resolveReason.type === 'timeout') { - return `Terminal command is running in the background in terminal ${bgTerminalId}. Here were the outputs after ${MAX_TERMINAL_INACTIVE_TIME} seconds:\n${result_}` - } + return `${result_}\n(exit code ${resolveReason.exitCode})` } // normal command - else { - if (resolveReason.type === 'timeout') { - return `Terminal command ran, but was interrupted after ${MAX_TERMINAL_INACTIVE_TIME}s of inactivity and did not necessarily finish successfully. Full output:\n${result_}` - } + if (resolveReason.type === 'timeout') { + return `${result_}\nTerminal command ran, but was interrupted by Void after ${MAX_TERMINAL_INACTIVE_TIME}s of inactivity and did not necessarily finish successfully.` } - throw new Error(`Unexpected internal error: Terminal command did not resolve with a valid reason.`) }, + + run_persistent_command: (params, result) => { + const { resolveReason, result: result_, } = result + const { persistentTerminalId } = params + // success + if (resolveReason.type === 'done') { + return `${result_}\n(exit code ${resolveReason.exitCode})` + } + // bg command + if (resolveReason.type === 'timeout') { + return `${result_}\nTerminal command is running in terminal ${persistentTerminalId}. The given outputs are the results after ${MAX_TERMINAL_BG_COMMAND_TIME} seconds.` + } + throw new Error(`Unexpected internal error: Terminal command did not resolve with a valid reason.`) + }, + open_persistent_terminal: (_params, result) => { - const { terminalId } = result; - return `Successfully created background terminal with ID ${terminalId}`; + const { persistentTerminalId } = result; + return `Successfully created persistent terminal. persistentTerminalId="${persistentTerminalId}"`; }, kill_persistent_terminal: (params, _result) => { - return `Successfully closed terminal ${params.terminalId}.`; + return `Successfully closed terminal "${params.persistentTerminalId}".`; }, } diff --git a/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts b/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts index 31666fb6..02ba06a1 100644 --- a/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts +++ b/src/vs/workbench/contrib/void/browser/voidUpdateActions.ts @@ -21,7 +21,7 @@ import { IAction } from '../../../../base/common/actions.js'; const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifService: INotificationService, updateService: IUpdateService) => { - const message = res?.message || 'This is a very old version of Void, please download the latest version! [Void Editor](https://voideditor.com/download-beta)!' + const message = res?.message || 'This is a very old version of Void, please download the latest version! [Void Editor](https://voideditor-test.com/download-beta)!' let actions: INotificationActions | undefined @@ -37,7 +37,7 @@ const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifSe class: undefined, run: () => { const { window } = dom.getActiveWindow() - window.open('https://voideditor.com/download-beta') + window.open('https://voideditor-test.com/download-beta') } }) } @@ -90,7 +90,7 @@ const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifSe class: undefined, run: () => { const { window } = dom.getActiveWindow() - window.open('https://voideditor.com/') + window.open('https://voideditor-test.com/') } }) @@ -125,7 +125,7 @@ const notifyUpdate = (res: VoidCheckUpdateRespose & { message: string }, notifSe // }) } const notifyErrChecking = (notifService: INotificationService) => { - const message = `Void Error: There was an error checking for updates. If this persists, please get in touch or reinstall Void [here](https://voideditor.com/download-beta)!` + const message = `Void Error: There was an error checking for updates. If this persists, please get in touch or reinstall Void [here](https://voideditor-test.com/download-beta)!` notifService.notify({ severity: Severity.Info, message: message, diff --git a/src/vs/workbench/contrib/void/common/modelCapabilities.ts b/src/vs/workbench/contrib/void/common/modelCapabilities.ts index 521d74bb..7fad5d59 100644 --- a/src/vs/workbench/contrib/void/common/modelCapabilities.ts +++ b/src/vs/workbench/contrib/void/common/modelCapabilities.ts @@ -88,7 +88,7 @@ export const defaultModelsOfProvider = { ], gemini: [ // https://ai.google.dev/gemini-api/docs/models/gemini 'gemini-2.5-pro-exp-03-25', - 'gemini-2.0-flash', + 'gemini-2.5-flash-preview-04-17', 'gemini-2.0-flash-lite', ], deepseek: [ // https://api-docs.deepseek.com/quick_start/pricing @@ -633,6 +633,15 @@ const xAISettings: VoidStaticProviderInfo = { // ---------------- GEMINI ---------------- const geminiModelOptions = { // https://ai.google.dev/gemini-api/docs/pricing + 'gemini-2.5-flash-preview-04-17': { + contextWindow: 1_048_576, + maxOutputTokens: 8_192, + cost: { input: 0.15, output: .60 }, // TODO $3.50 output with thinking not included + downloadable: false, + supportsFIM: false, + supportsSystemMessage: 'system-role', + reasoningCapabilities: false, + }, 'gemini-2.5-pro-exp-03-25': { contextWindow: 1_048_576, maxOutputTokens: 8_192, diff --git a/src/vs/workbench/contrib/void/common/prompt/prompts.ts b/src/vs/workbench/contrib/void/common/prompt/prompts.ts index f1305896..61aeacc1 100644 --- a/src/vs/workbench/contrib/void/common/prompt/prompts.ts +++ b/src/vs/workbench/contrib/void/common/prompt/prompts.ts @@ -7,7 +7,7 @@ import { EndOfLinePreference } from '../../../../../editor/common/model.js'; import { StagingSelectionItem } from '../chatThreadServiceTypes.js'; import { os } from '../helpers/systemInfo.js'; import { RawToolParamsObj } from '../sendLLMMessageTypes.js'; -import { approvalTypeOfToolName, ToolResultType } from '../toolsServiceTypes.js'; +import { approvalTypeOfToolName, ToolCallParams, ToolResultType } from '../toolsServiceTypes.js'; import { IVoidModelService } from '../voidModelService.js'; import { ChatMode } from '../voidSettingsTypes.js'; @@ -27,12 +27,14 @@ export const MAX_CHILDREN_URIs_PAGE = 500 // terminal tool info export const MAX_TERMINAL_CHARS = 100_000 export const MAX_TERMINAL_INACTIVE_TIME = 8 // seconds +export const MAX_TERMINAL_BG_COMMAND_TIME = 5 // Maximum character limits for prefix and suffix context export const MAX_PREFIX_SUFFIX_CHARS = 20_000 + // ======================================================== tools ======================================================== const changesExampleContent = `\ // ... existing code ... @@ -43,12 +45,12 @@ const changesExampleContent = `\ // {{change 3}} // ... existing code ...` -const editToolDescriptionExample = `\ +const editToolDiffExample = `\ ${tripleTick[0]} ${changesExampleContent} ${tripleTick[1]}` -const fileNameEditExample = `${tripleTick[0]}typescript +const chatSuggestionDiffExample = `${tripleTick[0]}typescript /Users/username/Dekstop/my_project/app.ts ${changesExampleContent} ${tripleTick[1]}` @@ -74,173 +76,188 @@ const paginationParam = { } as const +const terminalDescHelper = `You can use this tool to run any command: sed, grep, etc. Do not edit any files with this tool; use edit_file instead. When working with git and other tools that open an editor (e.g. git diff), you should pipe to cat to get all results and not get stuck in vim.` +const cwdHelper = 'Optional. The directory in which to run the command. Defaults to the first workspace folder.' -// export type SnakeCase = -// // exact acronym URI -// S extends 'URI' ? 'uri' -// // suffix URI: e.g. 'rootURI' -> snakeCase('root') + '_uri' -// : S extends `${infer Prefix}URI` ? `${SnakeCase}_uri` -// // default: for each char, prefix '_' on uppercase letters -// : S extends `${infer C}${infer Rest}` -// ? `${C extends Lowercase ? C : `_${Lowercase}`}${SnakeCase}` -// : S; +export type SnakeCase = + // exact acronym URI + S extends 'URI' ? 'uri' + // suffix URI: e.g. 'rootURI' -> snakeCase('root') + '_uri' + : S extends `${infer Prefix}URI` ? `${SnakeCase}_uri` + // default: for each char, prefix '_' on uppercase letters + : S extends `${infer C}${infer Rest}` + ? `${C extends Lowercase ? C : `_${Lowercase}`}${SnakeCase}` + : S; -// export type SnakeCaseKeys> = { -// [K in keyof T as SnakeCase>]: T[K] -// }; +export type SnakeCaseKeys> = { + [K in keyof T as SnakeCase>]: T[K] +}; - - -export const voidTools = { - // export const voidTools - // : { - // [T in keyof ToolCallParams]: { - // name: string; - // description: string; - // params: { - // [paramName in keyof SnakeCaseKeys]: { description: string } - // } - // } - // } - // = { - // --- context-gathering (read/search/list) --- - - read_file: { - name: 'read_file', - description: `Returns full contents of a given file.`, - params: { - ...uriParam('file'), - start_line: { description: 'Optional. Do NOT fill this in unless you already know the line numbers you need to search. Defaults to 1.' }, - end_line: { description: 'Optional. Do NOT fill this in unless you already know the line numbers you need to search. Defaults to Infinity.' }, - ...paginationParam, - }, - }, - - ls_dir: { - name: 'ls_dir', - description: `Lists all files and folders in the given URI.`, - params: { - uri: { description: `Optional. The FULL path to the ${'folder'}. Leave this as empty or "" to search all folders.` }, - ...paginationParam, - }, - }, - - get_dir_tree: { - name: 'get_dir_tree', - description: `This is a very effective way to learn about the user's codebase. Returns a tree diagram of all the files and folders in the given folder. `, - params: { - ...uriParam('folder') - } - }, - - // pathname_search: { - // name: 'pathname_search', - // description: `Returns all pathnames that match a given \`find\`-style query over the entire workspace. ONLY searches file names. ONLY searches the current workspace. You should use this when looking for a file with a specific name or path. ${paginationHelper.desc}`, - - search_pathnames_only: { - name: 'search_pathnames_only', - description: `Returns all pathnames that match a given query (searches ONLY file names). You should use this when looking for a file with a specific name or path.`, - params: { - query: { description: `Your query for the search.` }, - include_pattern: { description: 'Optional. Only fill this in if you need to limit your search because there were too many results.' }, - ...paginationParam, - }, - }, - - - - search_for_files: { - name: 'search_for_files', - description: `Returns a list of file names whose content matches the given query. The query can be any substring or regex.`, - params: { - query: { description: `Your query for the search.` }, - search_in_folder: { description: 'Optional. Leave as blank by default. ONLY fill this in if your previous search with the same query was truncated. Searches descendants of this folder only.' }, - is_regex: { description: 'Optional. Default is false. Whether the query is a regex.' }, - ...paginationParam, - }, - }, - - // add new search_in_file tool - search_in_file: { - name: 'search_in_file', - description: `Returns an array of all the start line numbers where the content appears in the file.`, - params: { - ...uriParam('file'), - query: { description: 'The string or regex to search for in the file.' }, - is_regex: { description: 'Optional. Default is false. Whether the query is a regex.' } - } - }, - - read_lint_errors: { - name: 'read_lint_errors', - description: `Returns all lint errors on a given file.`, - params: { - ...uriParam('file'), - }, - }, - - // --- editing (create/delete) --- - - create_file_or_folder: { - name: 'create_file_or_folder', - description: `Create a file or folder at the given path. To create a folder, the path MUST end with a trailing slash.`, - params: { - ...uriParam('file or folder'), - }, - }, - - delete_file_or_folder: { - name: 'delete_file_or_folder', - description: `Delete a file or folder at the given path.`, - params: { - ...uriParam('file or folder'), - params: { description: 'Optional. Return -r here to delete recursively.' } - }, - }, - - edit_file: { // APPLY TOOL - name: 'edit_file', - description: `Edits the contents of a file given the file's URI and a description.`, - params: { - ...uriParam('file'), - change_diff: { - description: `\ -A code diff describing the change to make to the file. \ +const applyToolDescription = (type: 'edit tool' | 'chat suggestion') => `\ +${type === 'edit tool' ? 'A' : 'a'} code diff describing the change to make to the file. \ Your DIFF is the only context that will be given to another LLM to apply the change, so it must be accurate and complete. \ Your DIFF MUST be wrapped in triple backticks. \ NEVER re-write the whole file. Always bias towards writing as little as possible. \ Use comments like "// ... existing code ..." to condense your writing. \ -Here's an example of a good output:\n${editToolDescriptionExample}` +Here's an example of a good output:\n${type === 'edit tool' ? editToolDiffExample : chatSuggestionDiffExample}` + + +// export const voidTools = { +export const voidTools + : { + [T in keyof ToolCallParams]: { + name: string; + description: string; + // more params can be generated than exist here, but these params must be a subset of them + params: Partial<{ [paramName in keyof SnakeCaseKeys]: { description: string } }> + } + } + = { + // --- context-gathering (read/search/list) --- + + read_file: { + name: 'read_file', + description: `Returns full contents of a given file.`, + params: { + ...uriParam('file'), + start_line: { description: 'Optional. Do NOT fill this in unless you already know the line numbers you need to search. Defaults to 1.' }, + end_line: { description: 'Optional. Do NOT fill this in unless you already know the line numbers you need to search. Defaults to Infinity.' }, + ...paginationParam, + }, + }, + + ls_dir: { + name: 'ls_dir', + description: `Lists all files and folders in the given URI.`, + params: { + uri: { description: `Optional. The FULL path to the ${'folder'}. Leave this as empty or "" to search all folders.` }, + ...paginationParam, + }, + }, + + get_dir_tree: { + name: 'get_dir_tree', + description: `This is a very effective way to learn about the user's codebase. Returns a tree diagram of all the files and folders in the given folder. `, + params: { + ...uriParam('folder') } }, - }, - run_command: { - name: 'run_command', - description: `Runs a terminal command and waits for the result (times out after ${MAX_TERMINAL_INACTIVE_TIME}s of inactivity). You can use this tool to run any command: sed, grep, etc. Do not edit any files with this tool; use edit_file instead. When working with git and other tools that open an editor (e.g. git diff), you should pipe to cat to get all results and not get stuck in vim.`, - params: { - command: { description: 'The terminal command to run.' }, - bg_terminal_id: { description: 'Optional. This only applies to terminals that have been opened with open_persistent_terminal. Runs the command in the terminal with the specified ID.' }, + // pathname_search: { + // name: 'pathname_search', + // description: `Returns all pathnames that match a given \`find\`-style query over the entire workspace. ONLY searches file names. ONLY searches the current workspace. You should use this when looking for a file with a specific name or path. ${paginationHelper.desc}`, + + search_pathnames_only: { + name: 'search_pathnames_only', + description: `Returns all pathnames that match a given query (searches ONLY file names). You should use this when looking for a file with a specific name or path.`, + params: { + query: { description: `Your query for the search.` }, + include_pattern: { description: 'Optional. Only fill this in if you need to limit your search because there were too many results.' }, + ...paginationParam, + }, }, - }, - - open_persistent_terminal: { - name: 'open_persistent_terminal', - description: `Use this tool when you want to run a terminal command indefinitely, like a dev server (eg \`npm run dev\`), a background listener, etc. Opens a new terminal in the user's environment which will not awaited for or killed.`, - params: {} - }, - kill_persistent_terminal: { - name: 'kill_persistent_terminal', - description: `Closes a BG terminal with the given ID.`, - params: { terminal_id: { description: `The terminal ID to interrupt and close.` } } - } - // go_to_definition - // go_to_usages -} satisfies { [T in keyof ToolResultType]: InternalToolInfo } + search_for_files: { + name: 'search_for_files', + description: `Returns a list of file names whose content matches the given query. The query can be any substring or regex.`, + params: { + query: { description: `Your query for the search.` }, + search_in_folder: { description: 'Optional. Leave as blank by default. ONLY fill this in if your previous search with the same query was truncated. Searches descendants of this folder only.' }, + is_regex: { description: 'Optional. Default is false. Whether the query is a regex.' }, + ...paginationParam, + }, + }, + + // add new search_in_file tool + search_in_file: { + name: 'search_in_file', + description: `Returns an array of all the start line numbers where the content appears in the file.`, + params: { + ...uriParam('file'), + query: { description: 'The string or regex to search for in the file.' }, + is_regex: { description: 'Optional. Default is false. Whether the query is a regex.' } + } + }, + + read_lint_errors: { + name: 'read_lint_errors', + description: `Returns all lint errors on a given file.`, + params: { + ...uriParam('file'), + }, + }, + + // --- editing (create/delete) --- + + create_file_or_folder: { + name: 'create_file_or_folder', + description: `Create a file or folder at the given path. To create a folder, the path MUST end with a trailing slash.`, + params: { + ...uriParam('file or folder'), + }, + }, + + delete_file_or_folder: { + name: 'delete_file_or_folder', + description: `Delete a file or folder at the given path.`, + params: { + ...uriParam('file or folder'), + is_recursive: { description: 'Optional. Return true to delete recursively.' } + }, + }, + + edit_file: { // APPLY TOOL + name: 'edit_file', + description: `Edits the contents of a file given the file's URI and a description.`, + params: { + ...uriParam('file'), + change_diff: { + description: applyToolDescription('edit tool') + } + }, + }, + + run_command: { + name: 'run_command', + description: `Runs a terminal command and waits for the result (times out after ${MAX_TERMINAL_INACTIVE_TIME}s of inactivity). ${terminalDescHelper}`, + params: { + command: { description: 'The terminal command to run.' }, + cwd: { description: cwdHelper }, + }, + }, + + run_persistent_command: { + name: 'run_persistent_command', + description: `Runs a terminal command in the persistent terminal that you created with open_persistent_terminal (results after ${MAX_TERMINAL_BG_COMMAND_TIME} are returned, and command continues running in background). ${terminalDescHelper}`, + params: { + command: { description: 'The terminal command to run.' }, + persistent_terminal_id: { description: 'The ID of the terminal created using open_persistent_terminal.' }, + }, + }, + + + + open_persistent_terminal: { + name: 'open_persistent_terminal', + description: `Use this tool when you want to run a terminal command indefinitely, like a dev server (eg \`npm run dev\`), a background listener, etc. Opens a new terminal in the user's environment which will not awaited for or killed.`, + params: { + cwd: { description: cwdHelper }, + } + }, + kill_persistent_terminal: { + name: 'kill_persistent_terminal', + description: `Interrupts and closes a persistent terminal that you opened with open_persistent_terminal.`, + params: { persistent_terminal_id: { description: `The ID of the persistent terminal.` } } + } + + + // go_to_definition + // go_to_usages + + } satisfies { [T in keyof ToolResultType]: InternalToolInfo } export type ToolName = keyof ToolResultType @@ -329,16 +346,16 @@ Please assist the user with their query.`) - ${os} -- Open workspaces: -${workspaceFolders.join('\n') || 'NO WORKSPACE OPEN'} +- The user's workspace contains these folders: +${workspaceFolders.join('\n') || 'NO FOLDERS OPEN'} - Active file: ${activeURI} - Open files: -${openedURIs.join('\n') || 'NO OPENED EDITORS'}${''/* separator */}${mode === 'agent' && runningTerminalIds.length !== 0 ? ` +${openedURIs.join('\n') || 'NO OPENED FILES'}${''/* separator */}${mode === 'agent' && runningTerminalIds.length !== 0 ? ` -- Existing terminal IDs: ${runningTerminalIds.join(', ')}` : ''} +- Existing persistent terminal IDs: ${runningTerminalIds.join(', ')}` : ''} `) @@ -368,7 +385,7 @@ ${directoryStr} details.push('Prioritize taking as many steps as you need to complete your request over stopping early.') details.push(`You will OFTEN need to gather context before making a change. Do not immediately make a change unless you have ALL relevant context.`) details.push(`ALWAYS have maximal certainty in a change BEFORE you make it. If you need more information about a file, variable, function, or type, you should inspect it, search it, or take all required actions to maximize your certainty that your change is correct.`) - details.push(`NEVER modify a file outside the user's workspace(s) without permission from the user.`) + details.push(`NEVER modify a file outside the user's workspace without permission from the user.`) } if (mode === 'gather') { @@ -383,12 +400,8 @@ ${directoryStr} - The remaining contents of the file should proceed as usual.`) details.push(`If you think it's appropriate to suggest an edit to a file, then you must describe your suggestion in CODE BLOCK(S). -- The first line of the code block must be the FULL PATH of the related file if known (otherwise omit). -- The remaining contents should be \ -a brief code description of the change you want to make, with comments like "// ... existing code ..." to condense your writing. \ -NEVER re-write the whole file. Instead, use comments like "// ... existing code ...". Bias towards writing as little as possible. \ -Here's an example of a good edit suggestion: -${fileNameEditExample}.`) +- The first line of the code block must be the FULL PATH of the related file. +- The remaining contents should be ${applyToolDescription('chat suggestion')}`) } details.push(`NEVER write the FULL PATH of a file when speaking with the user. Just write the file name ONLY.`) diff --git a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts index b234689c..63bfc997 100644 --- a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts +++ b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts @@ -21,6 +21,7 @@ export const approvalTypeOfToolName: Partial<{ [T in ToolName]?: 'edits' | 'term 'delete_file_or_folder': 'edits', 'edit_file': 'edits', 'run_command': 'terminal', + 'run_persistent_command': 'terminal', } @@ -46,9 +47,10 @@ export type ToolCallParams = { 'create_file_or_folder': { uri: URI, isFolder: boolean }, 'delete_file_or_folder': { uri: URI, isRecursive: boolean, isFolder: boolean }, // --- - 'run_command': { command: string; bgTerminalId: string | null }, - 'open_persistent_terminal': {}, - 'kill_persistent_terminal': { terminalId: string }, + 'run_command': { command: string; cwd: string | null, terminalId: string }, + 'open_persistent_terminal': { cwd: string | null }, + 'run_persistent_command': { command: string; persistentTerminalId: string }, + 'kill_persistent_terminal': { persistentTerminalId: string }, } // RESULT OF TOOL CALL @@ -66,7 +68,8 @@ export type ToolResultType = { 'delete_file_or_folder': {}, // --- 'run_command': { result: string; resolveReason: TerminalResolveReason; }, - 'open_persistent_terminal': { terminalId: string }, + 'run_persistent_command': { result: string; resolveReason: TerminalResolveReason; }, + 'open_persistent_terminal': { persistentTerminalId: string }, 'kill_persistent_terminal': {}, } diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/extractGrammar.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/extractGrammar.ts index 3e2031f1..b90dbafa 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/extractGrammar.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/extractGrammar.ts @@ -64,7 +64,7 @@ export const extractReasoningWrapper = ( // until found the second think tag, keep adding to fullReasoning if (!foundTag2) { const endsWithTag2 = endsWithAnyPrefixOf(fullText_, thinkTags[1]) - if (endsWithTag2) { + if (endsWithTag2 && endsWithTag2 !== thinkTags[1]) { // if ends with any partial part (full is fine) // console.log('endsWith2', { fullTextSoFar, fullReasoningSoFar }) // wait until we get the full tag or know more return diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts index 232bdfab..9209c685 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts @@ -82,7 +82,7 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ baseURL: 'https://openrouter.ai/api/v1', apiKey: thisConfig.apiKey, defaultHeaders: { - 'HTTP-Referer': 'https://voideditor.com', // Optional, for including your app on openrouter.ai rankings. + 'HTTP-Referer': 'https://voideditor-test.com', // Optional, for including your app on openrouter.ai rankings. 'X-Title': 'Void', // Optional. Shows in rankings on openrouter.ai. }, ...commonPayloadOpts, diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts index a7c440d4..070e2f34 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts @@ -32,6 +32,15 @@ export const sendLLMMessage = async ({ // only captures number of messages and message "shape", no actual code, instructions, prompts, etc const captureLLMEvent = (eventId: string, extras?: object) => { + + let totalTokens = 0 + if (messagesType === 'chatMessages') { + for (const m of messages_) totalTokens += m.content.length + } + else { + totalTokens = messages_.prefix.length + messages_.suffix.length + } + metricsService.capture(eventId, { providerName, modelName, @@ -40,14 +49,12 @@ export const sendLLMMessage = async ({ ...messagesType === 'chatMessages' ? { numMessages: messages_?.length, messagesShape: messages_?.map(msg => ({ role: msg.role, length: msg.content.length })), - origNumMessages: messages_?.length, - origMessagesShape: messages_?.map(msg => ({ role: msg.role, length: msg.content.length })), } : messagesType === 'FIMMessage' ? { prefixLength: messages_.prefix.length, suffixLength: messages_.suffix.length, } : {}, - + totalTokens, ...loggingExtras, ...extras, }) @@ -94,10 +101,11 @@ export const sendLLMMessage = async ({ } abortRef_.current = onAbort + if (messagesType === 'chatMessages') - captureLLMEvent(`${loggingName} - Sending Message`, { messageLength: messages_?.[messages_.length - 1]?.content.length }) + captureLLMEvent(`${loggingName} - Sending Message`, { userMessageLength: messages_?.[messages_.length - 1]?.content.length }) else if (messagesType === 'FIMMessage') - captureLLMEvent(`${loggingName} - Sending FIM`, { prefixLen: messages_?.prefix?.length, suffixLen: messages_?.suffix?.length }) // TODO!!! add more metrics for FIM + captureLLMEvent(`${loggingName} - Sending FIM`, { prefixLen: messages_?.prefix?.length, suffixLen: messages_?.suffix?.length }) try { diff --git a/src/vs/workbench/contrib/void/electron-main/metricsMainService.ts b/src/vs/workbench/contrib/void/electron-main/metricsMainService.ts index bfc0a8c9..a7d5e559 100644 --- a/src/vs/workbench/contrib/void/electron-main/metricsMainService.ts +++ b/src/vs/workbench/contrib/void/electron-main/metricsMainService.ts @@ -96,7 +96,7 @@ export class MetricsMainService extends Disposable implements IMetricsService { // very important to await whenReady! await this._appStorage.whenReady - const { commit, version, voidVersion, quality } = this._productService + const { commit, version, voidVersion, release, quality } = this._productService const isDevMode = !this._envMainService.isBuilt // found in abstractUpdateService.ts @@ -104,7 +104,8 @@ export class MetricsMainService extends Disposable implements IMetricsService { this._initProperties = { commit, vscodeVersion: version, - voidVersion, + voidVersion: voidVersion, + release, os, quality, distinctId: this.distinctId, diff --git a/src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts b/src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts index c8ef9e64..c1a42ec2 100644 --- a/src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts +++ b/src/vs/workbench/contrib/void/electron-main/voidUpdateMainService.ts @@ -89,12 +89,12 @@ export class VoidMainUpdateService extends Disposable implements IVoidUpdateServ private async _manualCheckGHTagIfDisabled(explicit: boolean): Promise { try { - const response = await fetch('https://api.github.com/repos/voideditor/binaries/releases/latest'); + const response = await fetch('https://api.github.com/repos/voideditor-test/binaries/releases/latest'); const data = await response.json(); const version = data.tag_name; - const myVersion = `${this._productService.voidVersion}.${this._productService.release}` + const myVersion = `${this._productService.version}.${this._productService.release}` const latestVersion = version const isUpToDate = myVersion === latestVersion // only makes sense if response.ok diff --git a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts index 6c61a590..52abe858 100644 --- a/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts @@ -81,8 +81,9 @@ export class NativeDialogHandler extends AbstractDialogHandler { const detailString = (useAgo: boolean): string => { return localize({ key: 'aboutDetail', comment: ['Electron, Chromium, Node.js and V8 are product names that need no translation'] }, - "Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nElectronBuildId: {4}\nChromium: {5}\nNode.js: {6}\nV8: {7}\nOS: {8}", + "VSCode Version: {0}\nVoid Version: {1}\nCommit: {2}\nDate: {3}\nElectron: {4}\nElectronBuildId: {5}\nChromium: {6}\nNode.js: {7}\nV8: {8}\nOS: {9}", version, + this.productService.voidVersion || 'Unknown', // Void added this this.productService.commit || 'Unknown', this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', process.versions['electron'], diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index e522238e..48645f79 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -328,7 +328,8 @@ import './contrib/surveys/browser/nps.contribution.js'; import './contrib/surveys/browser/languageSurveys.contribution.js'; // Welcome -import './contrib/welcomeGettingStarted/browser/gettingStarted.contribution.js'; +// Void commented this out +// import './contrib/welcomeGettingStarted/browser/gettingStarted.contribution.js'; import './contrib/welcomeWalkthrough/browser/walkThrough.contribution.js'; import './contrib/welcomeViews/common/viewsWelcome.contribution.js'; import './contrib/welcomeViews/common/newFile.contribution.js';