From d154d059a607e61badf6528e29d9e033a2427fe7 Mon Sep 17 00:00:00 2001 From: Nissa Seru <119150866+nissa-seru@users.noreply.github.com> Date: Fri, 31 Jan 2025 00:40:50 -0500 Subject: [PATCH 01/48] Enable separate config for truncation for models without context caching --- src/core/Cline.ts | 33 ++++++++++++-------- src/core/sliding-window/index.ts | 52 +++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 0c0bd37050..3299b0cab0 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -53,7 +53,7 @@ import { AssistantMessageContent, parseAssistantMessage, ToolParamName, ToolUseN import { formatResponse } from "./prompts/responses" import { SYSTEM_PROMPT } from "./prompts/system" import { modes, defaultModeSlug, getModeBySlug } from "../shared/modes" -import { truncateHalfConversation } from "./sliding-window" +import { truncateConversationIfNeeded } from "./sliding-window" import { ClineProvider, GlobalFileNames } from "./webview/ClineProvider" import { detectCodeOmission } from "../integrations/editor/detect-omission" import { BrowserSession } from "../services/browser/BrowserSession" @@ -837,18 +837,25 @@ export class Cline { // If the previous API request's total token usage is close to the context window, truncate the conversation history to free up space for the new request if (previousApiReqIndex >= 0) { - const previousRequest = this.clineMessages[previousApiReqIndex] - if (previousRequest && previousRequest.text) { - const { tokensIn, tokensOut, cacheWrites, cacheReads }: ClineApiReqInfo = JSON.parse( - previousRequest.text, - ) - const totalTokens = (tokensIn || 0) + (tokensOut || 0) + (cacheWrites || 0) + (cacheReads || 0) - const contextWindow = this.api.getModel().info.contextWindow || 128_000 - const maxAllowedSize = Math.max(contextWindow - 40_000, contextWindow * 0.8) - if (totalTokens >= maxAllowedSize) { - const truncatedMessages = truncateHalfConversation(this.apiConversationHistory) - await this.overwriteApiConversationHistory(truncatedMessages) - } + const previousRequest = this.clineMessages[previousApiReqIndex]?.text + if (!previousRequest) return + + const { + tokensIn = 0, + tokensOut = 0, + cacheWrites = 0, + cacheReads = 0, + }: ClineApiReqInfo = JSON.parse(previousRequest) + const totalTokens = tokensIn + tokensOut + cacheWrites + cacheReads + + const trimmedMessages = truncateConversationIfNeeded( + this.apiConversationHistory, + totalTokens, + this.api.getModel().info, + ) + + if (trimmedMessages !== this.apiConversationHistory) { + await this.overwriteApiConversationHistory(trimmedMessages) } } diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index caa604bc57..981d02fbae 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -1,4 +1,5 @@ import { Anthropic } from "@anthropic-ai/sdk" +<<<<<<< HEAD /* We can't implement a dynamically updating sliding window as it would break prompt cache @@ -9,18 +10,53 @@ Therefore, this function should only be called when absolutely necessary to fit context limits, not as a continuous process. */ export function truncateHalfConversation( +======= +import { ModelInfo } from "../../shared/api" +import { MessageParam } from "@anthropic-ai/sdk/resources/messages.mjs" + +export function truncateConversation( +>>>>>>> 455d850c (Enable separate config for truncation for models without context caching) messages: Anthropic.Messages.MessageParam[], + fracToRemove: number, ): Anthropic.Messages.MessageParam[] { - // API expects messages to be in user-assistant order, and tool use messages must be followed by tool results. We need to maintain this structure while truncating. - - // Always keep the first Task message (this includes the project's file structure in environment_details) const truncatedMessages = [messages[0]] - - // Remove half of user-assistant pairs - const messagesToRemove = Math.floor(messages.length / 4) * 2 // has to be even number - - const remainingMessages = messages.slice(messagesToRemove + 1) // has to start with assistant message since tool result cannot follow assistant message with no tool use + const rawMessagesToRemove = Math.floor((messages.length - 1) * fracToRemove) + const messagesToRemove = rawMessagesToRemove - (rawMessagesToRemove % 2) + const remainingMessages = messages.slice(messagesToRemove + 1) truncatedMessages.push(...remainingMessages) return truncatedMessages } + +export function truncateConversationIfNeeded( + messages: MessageParam[], + totalTokens: number, + modelInfo: ModelInfo, +): MessageParam[] { + if (modelInfo.supportsPromptCache) { + return totalTokens < getMaxTokensForPromptCachingModels(modelInfo) + ? messages + : truncateConversation(messages, getTruncFractionForPromptCachingModels(modelInfo)) + } else { + const thresh = getMaxTokensForNonPromptCachingModels(modelInfo) + return totalTokens < thresh + ? messages + : truncateConversation(messages, getTruncFractionForNonPromptCachingModels(modelInfo)) + } +} + +function getMaxTokensForPromptCachingModels(modelInfo: ModelInfo): number { + return Math.max(modelInfo.contextWindow - 40_000, modelInfo.contextWindow * 0.8) +} + +function getTruncFractionForPromptCachingModels(modelInfo: ModelInfo): number { + return Math.min(80_000, modelInfo.contextWindow * 0.4) +} + +function getMaxTokensForNonPromptCachingModels(modelInfo: ModelInfo): number { + return Math.max(modelInfo.contextWindow - 40_000, modelInfo.contextWindow * 0.8) +} + +function getTruncFractionForNonPromptCachingModels(modelInfo: ModelInfo): number { + return Math.min(80_000, modelInfo.contextWindow * 0.4) +} From 9da39e42e1b72f0421480e10e867e0f3b71e8da9 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 2 Feb 2025 01:23:45 -0500 Subject: [PATCH 02/48] Fix conflict --- src/core/sliding-window/index.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index 981d02fbae..6fbd5b8a9c 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -1,21 +1,8 @@ import { Anthropic } from "@anthropic-ai/sdk" -<<<<<<< HEAD - -/* -We can't implement a dynamically updating sliding window as it would break prompt cache -every time. To maintain the benefits of caching, we need to keep conversation history -static. This operation should be performed as infrequently as possible. If a user reaches -a 200k context, we can assume that the first half is likely irrelevant to their current task. -Therefore, this function should only be called when absolutely necessary to fit within -context limits, not as a continuous process. -*/ -export function truncateHalfConversation( -======= import { ModelInfo } from "../../shared/api" import { MessageParam } from "@anthropic-ai/sdk/resources/messages.mjs" export function truncateConversation( ->>>>>>> 455d850c (Enable separate config for truncation for models without context caching) messages: Anthropic.Messages.MessageParam[], fracToRemove: number, ): Anthropic.Messages.MessageParam[] { From fef95e10b83a9bc94d8956e68d4ebfa208188091 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sun, 2 Feb 2025 01:34:45 -0500 Subject: [PATCH 03/48] Fix type --- src/core/sliding-window/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index 6fbd5b8a9c..3ecb785f5e 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -1,6 +1,5 @@ import { Anthropic } from "@anthropic-ai/sdk" import { ModelInfo } from "../../shared/api" -import { MessageParam } from "@anthropic-ai/sdk/resources/messages.mjs" export function truncateConversation( messages: Anthropic.Messages.MessageParam[], @@ -16,10 +15,10 @@ export function truncateConversation( } export function truncateConversationIfNeeded( - messages: MessageParam[], + messages: Anthropic.Messages.MessageParam[], totalTokens: number, modelInfo: ModelInfo, -): MessageParam[] { +): Anthropic.Messages.MessageParam[] { if (modelInfo.supportsPromptCache) { return totalTokens < getMaxTokensForPromptCachingModels(modelInfo) ? messages From 3492f79f37b1ba81d19af080ea10172a0364aac7 Mon Sep 17 00:00:00 2001 From: Nissa Seru <119150866+nissa-seru@users.noreply.github.com> Date: Sun, 2 Feb 2025 02:56:30 -0500 Subject: [PATCH 04/48] Remove unnecessary variable, add JSDocs --- src/core/sliding-window/index.ts | 57 +++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index 3ecb785f5e..9e98ba17d7 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -1,6 +1,16 @@ import { Anthropic } from "@anthropic-ai/sdk" import { ModelInfo } from "../../shared/api" +/** + * Truncates a conversation by removing a fraction of the messages. + * + * The first message is always retained, and a specified fraction (rounded to an even number) + * of messages from the beginning (excluding the first) is removed. + * + * @param {Anthropic.Messages.MessageParam[]} messages - The conversation messages. + * @param {number} fracToRemove - The fraction (between 0 and 1) of messages (excluding the first) to remove. + * @returns {Anthropic.Messages.MessageParam[]} The truncated conversation messages. + */ export function truncateConversation( messages: Anthropic.Messages.MessageParam[], fracToRemove: number, @@ -14,6 +24,18 @@ export function truncateConversation( return truncatedMessages } +/** + * Conditionally truncates the conversation messages if the total token count exceeds the model's limit. + * + * Depending on whether the model supports prompt caching, different maximum token thresholds + * and truncation fractions are used. If the current total tokens exceed the threshold, + * the conversation is truncated using the appropriate fraction. + * + * @param {Anthropic.Messages.MessageParam[]} messages - The conversation messages. + * @param {number} totalTokens - The total number of tokens in the conversation. + * @param {ModelInfo} modelInfo - Model metadata including context window size and prompt cache support. + * @returns {Anthropic.Messages.MessageParam[]} The original or truncated conversation messages. + */ export function truncateConversationIfNeeded( messages: Anthropic.Messages.MessageParam[], totalTokens: number, @@ -24,25 +46,52 @@ export function truncateConversationIfNeeded( ? messages : truncateConversation(messages, getTruncFractionForPromptCachingModels(modelInfo)) } else { - const thresh = getMaxTokensForNonPromptCachingModels(modelInfo) - return totalTokens < thresh + return totalTokens < getMaxTokensForNonPromptCachingModels(modelInfo) ? messages : truncateConversation(messages, getTruncFractionForNonPromptCachingModels(modelInfo)) } } +/** + * Calculates the maximum allowed tokens for models that support prompt caching. + * + * The maximum is computed as the greater of (contextWindow - 40000) and 80% of the contextWindow. + * + * @param {ModelInfo} modelInfo - The model information containing the context window size. + * @returns {number} The maximum number of tokens allowed for prompt caching models. + */ function getMaxTokensForPromptCachingModels(modelInfo: ModelInfo): number { return Math.max(modelInfo.contextWindow - 40_000, modelInfo.contextWindow * 0.8) } +/** + * Provides the fraction of messages to remove for models that support prompt caching. + * + * @param {ModelInfo} modelInfo - The model information (unused in current implementation). + * @returns {number} The truncation fraction for prompt caching models (fixed at 0.5). + */ function getTruncFractionForPromptCachingModels(modelInfo: ModelInfo): number { - return Math.min(80_000, modelInfo.contextWindow * 0.4) + return 0.5 } +/** + * Calculates the maximum allowed tokens for models that do not support prompt caching. + * + * The maximum is computed as the greater of (contextWindow - 40000) and 80% of the contextWindow. + * + * @param {ModelInfo} modelInfo - The model information containing the context window size. + * @returns {number} The maximum number of tokens allowed for non-prompt caching models. + */ function getMaxTokensForNonPromptCachingModels(modelInfo: ModelInfo): number { return Math.max(modelInfo.contextWindow - 40_000, modelInfo.contextWindow * 0.8) } +/** + * Provides the fraction of messages to remove for models that do not support prompt caching. + * + * @param {ModelInfo} modelInfo - The model information (unused in current implementation). + * @returns {number} The truncation fraction for non-prompt caching models (fixed at 0.1). + */ function getTruncFractionForNonPromptCachingModels(modelInfo: ModelInfo): number { - return Math.min(80_000, modelInfo.contextWindow * 0.4) + return 0.1 } From 11fc6da3927c68b74b041da8e4fc563a30ca8164 Mon Sep 17 00:00:00 2001 From: cte Date: Tue, 4 Feb 2025 08:27:05 -0800 Subject: [PATCH 05/48] VSCode styling for shadcn/ui + expose `container` prop in dropdown portals --- webview-ui/src/components/ui/button.tsx | 10 +++++----- webview-ui/src/components/ui/dropdown-menu.tsx | 10 ++++++---- webview-ui/src/index.css | 9 +++++++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/webview-ui/src/components/ui/button.tsx b/webview-ui/src/components/ui/button.tsx index 5bd00336b9..370ff4a19f 100644 --- a/webview-ui/src/components/ui/button.tsx +++ b/webview-ui/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-90", { variants: { variant: { @@ -17,10 +17,10 @@ const buttonVariants = cva( link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-9 w-9", + default: "h-7 px-3", + sm: "h-6 px-2 text-sm", + lg: "h-8 px-4 text-lg", + icon: "h-7 w-7", }, }, defaultVariants: { diff --git a/webview-ui/src/components/ui/dropdown-menu.tsx b/webview-ui/src/components/ui/dropdown-menu.tsx index 8508b55deb..098090fb31 100644 --- a/webview-ui/src/components/ui/dropdown-menu.tsx +++ b/webview-ui/src/components/ui/dropdown-menu.tsx @@ -53,9 +53,11 @@ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayNam const DropdownMenuContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - + React.ComponentPropsWithoutRef & { + container?: HTMLElement + } +>(({ className, sideOffset = 4, container, ...props }, ref) => ( + svg]:size-4 [&>svg]:shrink-0", + "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0 active:opacity-90", inset && "pl-8", className, )} diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 8069ca9195..194f421684 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -22,6 +22,11 @@ @plugin "tailwindcss-animate"; @theme { + --font-display: var(--vscode-font-family); + --text-sm: calc(var(--vscode-font-size) * 0.9); + --text-base: var(--vscode-font-size); + --text-lg: calc(var(--vscode-font-size) * 1.1); + --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); @@ -65,11 +70,11 @@ --secondary-foreground: var(--vscode-button-secondaryForeground); --muted: var(--vscode-disabledForeground); --muted-foreground: var(--vscode-descriptionForeground); - --accent: var(--vscode-input-border); + --accent: var(--vscode-list-hoverBackground); --accent-foreground: var(--vscode-button-foreground); --destructive: var(--vscode-errorForeground); --destructive-foreground: var(--vscode-button-foreground); - --border: var(--vscode-widget-border); + --border: var(--vscode-input-border); --input: var(--vscode-input-background); --ring: var(--vscode-input-border); --chart-1: var(--vscode-charts-red); From 14975311f50f40ecdd8e2d2d1d3ef79fed7c3717 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 13:29:47 -0500 Subject: [PATCH 06/48] v3.3.10 --- .changeset/nine-tables-cheat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nine-tables-cheat.md diff --git a/.changeset/nine-tables-cheat.md b/.changeset/nine-tables-cheat.md new file mode 100644 index 0000000000..7e48c235bf --- /dev/null +++ b/.changeset/nine-tables-cheat.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.3.10 From 1f3b07d62741c44eebf76d1b5f76f9aac37aeb07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Feb 2025 02:52:52 +0000 Subject: [PATCH 07/48] changeset version bump --- .changeset/blue-masks-camp.md | 5 ----- .changeset/breezy-badgers-refuse.md | 5 ----- .changeset/nine-tables-cheat.md | 5 ----- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 11 insertions(+), 18 deletions(-) delete mode 100644 .changeset/blue-masks-camp.md delete mode 100644 .changeset/breezy-badgers-refuse.md delete mode 100644 .changeset/nine-tables-cheat.md diff --git a/.changeset/blue-masks-camp.md b/.changeset/blue-masks-camp.md deleted file mode 100644 index a67e1c4d53..0000000000 --- a/.changeset/blue-masks-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) diff --git a/.changeset/breezy-badgers-refuse.md b/.changeset/breezy-badgers-refuse.md deleted file mode 100644 index 50cbbe9262..0000000000 --- a/.changeset/breezy-badgers-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Visual cleanup to the list of modes on the prompts tab diff --git a/.changeset/nine-tables-cheat.md b/.changeset/nine-tables-cheat.md deleted file mode 100644 index 7e48c235bf..0000000000 --- a/.changeset/nine-tables-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.3.10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd17bd2b9..2ad73d058e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Roo Code Changelog +## 3.3.10 + +### Patch Changes + +- Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) +- Visual cleanup to the list of modes on the prompts tab +- v3.3.10 + ## [3.3.9] - Add o3-mini-high and o3-mini-low diff --git a/package-lock.json b/package-lock.json index eecc0e681e..2c518b330e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.3.9", + "version": "3.3.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.3.9", + "version": "3.3.10", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.26.0", diff --git a/package.json b/package.json index a95ace9ee3..80528fdfd0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.", "publisher": "RooVeterinaryInc", - "version": "3.3.9", + "version": "3.3.10", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From 92cd81d66bd7b488095761fb5c1f7d3cd6dec255 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 22:22:03 -0500 Subject: [PATCH 08/48] Update CHANGELOG.md --- CHANGELOG.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ad73d058e..983d2bfac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,19 @@ # Roo Code Changelog -## 3.3.10 - -### Patch Changes +## [3.3.10] - Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) +- Fix pricing for o1-mini (thanks @hesara!) +- Fix context window size calculation (thanks @MuriloFP!) +- Improvements to experimental unified diff strategy and selection logic in code actions (thanks @nissa-seru!) +- Enable markdown formatting in o3 and o1 (thanks @nissa-seru!) +- Improved terminal shell detection logic (thanks @canvrno for the original and @nissa-seru for the port!) +- Fix occasional errors when switching between API profiles (thanks @samhvw8!) +- Visual improvements to the list of modes on the prompts tab +- Fix double-scrollbar in provider dropdown - Visual cleanup to the list of modes on the prompts tab -- v3.3.10 +- Improvements to the default prompts for Architect and Ask mode +- Allow switching between modes with slash messages like `/ask why is the sky blue?` ## [3.3.9] From 111020bb507abcea40c7cccc23d7592a4df03249 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 23:14:57 -0500 Subject: [PATCH 09/48] Removing docs (moving to another repo) --- .github/workflows/pages.yml | 44 ----- docs/Gemfile | 2 - docs/Gemfile.lock | 308 ---------------------------------- docs/_config.yml | 15 -- docs/getting-started/index.md | 10 -- docs/index.md | 9 - 6 files changed, 388 deletions(-) delete mode 100644 .github/workflows/pages.yml delete mode 100644 docs/Gemfile delete mode 100644 docs/Gemfile.lock delete mode 100644 docs/_config.yml delete mode 100644 docs/getting-started/index.md delete mode 100644 docs/index.md diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index ac551ebc85..0000000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Deploy Jekyll site to Pages - -on: - push: - branches: ["main"] - workflow_dispatch: - -permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 - with: - source: ./docs/ - destination: ./_site - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/docs/Gemfile b/docs/Gemfile deleted file mode 100644 index 91ceacd3cb..0000000000 --- a/docs/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source 'https://rubygems.org' -gem 'github-pages', group: :jekyll_plugins \ No newline at end of file diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock deleted file mode 100644 index a08fc8bb22..0000000000 --- a/docs/Gemfile.lock +++ /dev/null @@ -1,308 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (8.0.1) - base64 - benchmark (>= 0.3) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) - uri (>= 0.13.1) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - base64 (0.2.0) - benchmark (0.4.0) - bigdecimal (3.1.9) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) - colorator (1.1.0) - commonmarker (0.23.11) - concurrent-ruby (1.3.5) - connection_pool (2.5.0) - csv (3.3.2) - dnsruby (1.72.3) - base64 (~> 0.2.0) - simpleidn (~> 0.2.1) - drb (2.2.1) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - ethon (0.16.0) - ffi (>= 1.15.0) - eventmachine (1.2.7) - execjs (2.10.0) - faraday (2.12.2) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-net_http (3.4.0) - net-http (>= 0.5.0) - ffi (1.17.1-aarch64-linux-gnu) - ffi (1.17.1-aarch64-linux-musl) - ffi (1.17.1-arm-linux-gnu) - ffi (1.17.1-arm-linux-musl) - ffi (1.17.1-arm64-darwin) - ffi (1.17.1-x86_64-darwin) - ffi (1.17.1-x86_64-linux-gnu) - ffi (1.17.1-x86_64-linux-musl) - forwardable-extended (2.6.0) - gemoji (4.1.0) - github-pages (232) - github-pages-health-check (= 1.18.2) - jekyll (= 3.10.0) - jekyll-avatar (= 0.8.0) - jekyll-coffeescript (= 1.2.2) - jekyll-commonmark-ghpages (= 0.5.1) - jekyll-default-layout (= 0.1.5) - jekyll-feed (= 0.17.0) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.16.1) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.13.0) - kramdown (= 2.4.0) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.16.2, < 2.0) - rouge (= 3.30.0) - terminal-table (~> 1.4) - webrick (~> 1.8) - github-pages-health-check (1.18.2) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (>= 4, < 8) - public_suffix (>= 3.0, < 6.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (1.14.7) - concurrent-ruby (~> 1.0) - jekyll (3.10.0) - addressable (~> 2.4) - colorator (~> 1.0) - csv (~> 3.0) - em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - webrick (>= 1.0) - jekyll-avatar (0.8.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.2.2) - coffee-script (~> 2.2) - coffee-script-source (~> 1.12) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.5.1) - commonmarker (>= 0.23.7, < 1.1.0) - jekyll (>= 3.9, < 4.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.5) - jekyll (>= 3.0, < 5.0) - jekyll-feed (0.17.0) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.16.1) - jekyll (>= 3.4, < 5.0) - octokit (>= 4, < 7, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.13.0) - gemoji (>= 3, < 5) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - json (2.9.1) - kramdown (2.4.0) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.9.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.5) - mercenary (0.3.6) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.25.4) - net-http (0.6.0) - uri - nokogiri (1.18.2-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.2-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.18.2-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.2-arm-linux-musl) - racc (~> 1.4) - nokogiri (1.18.2-arm64-darwin) - racc (~> 1.4) - nokogiri (1.18.2-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.2-x86_64-linux-musl) - racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (5.1.1) - racc (1.8.1) - rb-fsevent (0.11.2) - rb-inotify (0.11.1) - ffi (~> 1.0) - rexml (3.4.0) - rouge (3.30.0) - rubyzip (2.4.1) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - securerandom (0.4.1) - simpleidn (0.2.3) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.1) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unicode-display_width (1.8.0) - uri (1.0.2) - webrick (1.9.1) - -PLATFORMS - aarch64-linux-gnu - aarch64-linux-musl - arm-linux-gnu - arm-linux-musl - arm64-darwin - x86_64-darwin - x86_64-linux-gnu - x86_64-linux-musl - -DEPENDENCIES - github-pages - -BUNDLED WITH - 2.5.18 diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 8d2cfe4a38..0000000000 --- a/docs/_config.yml +++ /dev/null @@ -1,15 +0,0 @@ -title: Roo Code Documentation -description: Documentation for the Roo Code project -remote_theme: just-the-docs/just-the-docs - -url: https://docs.roocode.com - -aux_links: - "Roo Code on GitHub": - - "//github.com/RooVetGit/Roo-Code" - -# Enable search -search_enabled: true - -# Enable dark mode -color_scheme: dark diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md deleted file mode 100644 index 9b0f385436..0000000000 --- a/docs/getting-started/index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Getting Started -layout: default -nav_order: 2 -has_children: true ---- - -# Getting Started with Roo Code - -This section will help you get up and running with Roo Code quickly. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 0cf6022436..0000000000 --- a/docs/index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Home -layout: home -nav_order: 1 ---- - -# Welcome to Roo Code Documentation - -This is the documentation for Roo Code. Choose a section from the navigation menu to get started. From d145039d72e97af81ba6d6ba9e26a242576f99e0 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 23:55:16 -0500 Subject: [PATCH 10/48] Safer profile path check --- .changeset/heavy-feet-judge.md | 5 +++++ src/utils/__tests__/shell.test.ts | 6 ++++++ src/utils/shell.ts | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .changeset/heavy-feet-judge.md diff --git a/.changeset/heavy-feet-judge.md b/.changeset/heavy-feet-judge.md new file mode 100644 index 0000000000..b9b3ca0f7b --- /dev/null +++ b/.changeset/heavy-feet-judge.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Safer shell profile path check diff --git a/src/utils/__tests__/shell.test.ts b/src/utils/__tests__/shell.test.ts index dee997a752..9c2b23aaa5 100644 --- a/src/utils/__tests__/shell.test.ts +++ b/src/utils/__tests__/shell.test.ts @@ -97,6 +97,12 @@ describe("Shell Detection Tests", () => { expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe") }) + it("handles undefined profile gracefully", () => { + // Mock a case where defaultProfileName exists but the profile doesn't + mockVsCodeConfig("windows", "NonexistentProfile", {}) + expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe") + }) + it("respects userInfo() if no VS Code config is available", () => { vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any ;(userInfo as any) = () => ({ shell: "C:\\Custom\\PowerShell.exe" }) diff --git a/src/utils/shell.ts b/src/utils/shell.ts index 8871550a0e..2f7ffb3a88 100644 --- a/src/utils/shell.ts +++ b/src/utils/shell.ts @@ -105,7 +105,7 @@ function getWindowsShellFromVSCode(): string | null { } // If there's a specific path, return that immediately - if (profile.path) { + if (profile?.path) { return profile.path } From 5297cad5e2f41f34e9add80f240dde5bda783a48 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 10:07:12 -0500 Subject: [PATCH 11/48] Revert "Merge pull request #764 from RooVetGit/slash_switch_modes" This reverts commit e3d7f25d262f0772b32d691012b6b140f597485e, reversing changes made to 55e8170369ddee3411ea85c76ff86f4b8b3bcf2b. --- src/core/Cline.ts | 46 +-------------------- src/shared/__tests__/modes.test.ts | 64 +----------------------------- src/shared/modes.ts | 33 --------------- 3 files changed, 2 insertions(+), 141 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 7595480efd..39013f0cb4 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -52,7 +52,7 @@ import { parseMentions } from "./mentions" import { AssistantMessageContent, parseAssistantMessage, ToolParamName, ToolUseName } from "./assistant-message" import { formatResponse } from "./prompts/responses" import { SYSTEM_PROMPT } from "./prompts/system" -import { modes, defaultModeSlug, getModeBySlug, parseSlashCommand } from "../shared/modes" +import { modes, defaultModeSlug, getModeBySlug } from "../shared/modes" import { truncateHalfConversation } from "./sliding-window" import { ClineProvider, GlobalFileNames } from "./webview/ClineProvider" import { detectCodeOmission } from "../integrations/editor/detect-omission" @@ -77,29 +77,6 @@ export class Cline { private terminalManager: TerminalManager private urlContentFetcher: UrlContentFetcher private browserSession: BrowserSession - - /** - * Processes a message for slash commands and handles mode switching if needed. - * @param message The message to process - * @returns The processed message with slash command removed if one was present - */ - private async handleSlashCommand(message: string): Promise { - if (!message) return message - - const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} - const slashCommand = parseSlashCommand(message, customModes) - - if (slashCommand) { - // Switch mode before processing the remaining message - const provider = this.providerRef.deref() - if (provider) { - await provider.handleModeSwitch(slashCommand.modeSlug) - return slashCommand.remainingMessage - } - } - - return message - } private didEditFile: boolean = false customInstructions?: string diffStrategy?: DiffStrategy @@ -378,11 +355,6 @@ export class Cline { } async handleWebviewAskResponse(askResponse: ClineAskResponse, text?: string, images?: string[]) { - // Process slash command if present - if (text) { - text = await this.handleSlashCommand(text) - } - this.askResponse = askResponse this.askResponseText = text this.askResponseImages = images @@ -465,22 +437,6 @@ export class Cline { this.apiConversationHistory = [] await this.providerRef.deref()?.postStateToWebview() - // Check for slash command if task is provided - if (task) { - const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} - const slashCommand = parseSlashCommand(task, customModes) - - if (slashCommand) { - // Switch mode before processing the remaining message - const provider = this.providerRef.deref() - if (provider) { - await provider.handleModeSwitch(slashCommand.modeSlug) - // Update task to be just the remaining message - task = slashCommand.remainingMessage - } - } - } - await this.say("text", task, images) let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images) diff --git a/src/shared/__tests__/modes.test.ts b/src/shared/__tests__/modes.test.ts index e373bc20ca..44d237630c 100644 --- a/src/shared/__tests__/modes.test.ts +++ b/src/shared/__tests__/modes.test.ts @@ -1,4 +1,4 @@ -import { isToolAllowedForMode, FileRestrictionError, ModeConfig, parseSlashCommand } from "../modes" +import { isToolAllowedForMode, FileRestrictionError, ModeConfig } from "../modes" describe("isToolAllowedForMode", () => { const customModes: ModeConfig[] = [ @@ -332,65 +332,3 @@ describe("FileRestrictionError", () => { expect(error.name).toBe("FileRestrictionError") }) }) - -describe("parseSlashCommand", () => { - const customModes: ModeConfig[] = [ - { - slug: "custom-mode", - name: "Custom Mode", - roleDefinition: "Custom role", - groups: ["read"], - }, - ] - - it("returns null for non-slash messages", () => { - expect(parseSlashCommand("hello world")).toBeNull() - expect(parseSlashCommand("code help me")).toBeNull() - }) - - it("returns null for incomplete commands", () => { - expect(parseSlashCommand("/")).toBeNull() - expect(parseSlashCommand("/code")).toBeNull() - expect(parseSlashCommand("/code ")).toBeNull() - }) - - it("returns null for invalid mode slugs", () => { - expect(parseSlashCommand("/invalid help me")).toBeNull() - expect(parseSlashCommand("/nonexistent do something")).toBeNull() - }) - - it("successfully parses valid commands", () => { - expect(parseSlashCommand("/code help me write tests")).toEqual({ - modeSlug: "code", - remainingMessage: "help me write tests", - }) - - expect(parseSlashCommand("/ask what is typescript?")).toEqual({ - modeSlug: "ask", - remainingMessage: "what is typescript?", - }) - - expect(parseSlashCommand("/architect plan this feature")).toEqual({ - modeSlug: "architect", - remainingMessage: "plan this feature", - }) - }) - - it("preserves whitespace in remaining message", () => { - expect(parseSlashCommand("/code help me write tests ")).toEqual({ - modeSlug: "code", - remainingMessage: "help me write tests", - }) - }) - - it("handles custom modes", () => { - expect(parseSlashCommand("/custom-mode do something", customModes)).toEqual({ - modeSlug: "custom-mode", - remainingMessage: "do something", - }) - }) - - it("returns null for invalid custom mode slugs", () => { - expect(parseSlashCommand("/invalid-custom do something", customModes)).toBeNull() - }) -}) diff --git a/src/shared/modes.ts b/src/shared/modes.ts index bf4735e3f7..f1b899cc5c 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -257,36 +257,3 @@ export function getCustomInstructions(modeSlug: string, customModes?: ModeConfig } return mode.customInstructions ?? "" } - -// Slash command parsing types and functions -export type SlashCommandResult = { - modeSlug: string - remainingMessage: string -} | null - -export function parseSlashCommand(message: string, customModes?: ModeConfig[]): SlashCommandResult { - // Check if message starts with a slash - if (!message.startsWith("/")) { - return null - } - - // Extract command (everything between / and first space) - const parts = message.trim().split(/\s+/) - if (parts.length < 2) { - return null // Need both command and message - } - - const command = parts[0].substring(1) // Remove leading slash - const remainingMessage = parts.slice(1).join(" ") - - // Validate command is a valid mode slug - const mode = getModeBySlug(command, customModes) - if (!mode) { - return null - } - - return { - modeSlug: command, - remainingMessage, - } -} From ebd9084e56a621470302764e44cc6d1f28a83847 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 4 Feb 2025 10:07:38 -0500 Subject: [PATCH 12/48] Use autocomplete instead for switching modes --- .../src/components/chat/ChatTextArea.tsx | 48 ++++++++++++++---- webview-ui/src/components/chat/ChatView.tsx | 2 +- .../src/components/chat/ContextMenu.tsx | 48 ++++++++++++++---- webview-ui/src/utils/context-mentions.ts | 50 +++++++++++++++++++ 4 files changed, 127 insertions(+), 21 deletions(-) diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index a20922db54..ae1b342dfe 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -179,6 +179,18 @@ const ChatTextArea = forwardRef( return } + if (type === ContextMenuOptionType.Mode && value) { + // Handle mode selection + setMode(value) + setInputValue("") + setShowContextMenu(false) + vscode.postMessage({ + type: "mode", + text: value, + }) + return + } + if ( type === ContextMenuOptionType.File || type === ContextMenuOptionType.Folder || @@ -242,7 +254,12 @@ const ChatTextArea = forwardRef( event.preventDefault() setSelectedMenuIndex((prevIndex) => { const direction = event.key === "ArrowUp" ? -1 : 1 - const options = getContextMenuOptions(searchQuery, selectedType, queryItems) + const options = getContextMenuOptions( + searchQuery, + selectedType, + queryItems, + getAllModes(customModes), + ) const optionsLength = options.length if (optionsLength === 0) return prevIndex @@ -272,9 +289,12 @@ const ChatTextArea = forwardRef( } if ((event.key === "Enter" || event.key === "Tab") && selectedMenuIndex !== -1) { event.preventDefault() - const selectedOption = getContextMenuOptions(searchQuery, selectedType, queryItems)[ - selectedMenuIndex - ] + const selectedOption = getContextMenuOptions( + searchQuery, + selectedType, + queryItems, + getAllModes(customModes), + )[selectedMenuIndex] if ( selectedOption && selectedOption.type !== ContextMenuOptionType.URL && @@ -340,6 +360,7 @@ const ChatTextArea = forwardRef( setInputValue, justDeletedSpaceAfterMention, queryItems, + customModes, ], ) @@ -360,13 +381,21 @@ const ChatTextArea = forwardRef( setShowContextMenu(showMenu) if (showMenu) { - const lastAtIndex = newValue.lastIndexOf("@", newCursorPosition - 1) - const query = newValue.slice(lastAtIndex + 1, newCursorPosition) - setSearchQuery(query) - if (query.length > 0) { + if (newValue.startsWith("/")) { + // Handle slash command + const query = newValue + setSearchQuery(query) setSelectedMenuIndex(0) } else { - setSelectedMenuIndex(3) // Set to "File" option by default + // Existing @ mention handling + const lastAtIndex = newValue.lastIndexOf("@", newCursorPosition - 1) + const query = newValue.slice(lastAtIndex + 1, newCursorPosition) + setSearchQuery(query) + if (query.length > 0) { + setSelectedMenuIndex(0) + } else { + setSelectedMenuIndex(3) // Set to "File" option by default + } } } else { setSearchQuery("") @@ -614,6 +643,7 @@ const ChatTextArea = forwardRef( setSelectedIndex={setSelectedMenuIndex} selectedType={selectedType} queryItems={queryItems} + modes={getAllModes(customModes)} /> )} diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index b1142fd5db..a102ca1fc2 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -878,7 +878,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie const placeholderText = useMemo(() => { const baseText = task ? "Type a message..." : "Type your task here..." - const contextText = "(@ to add context" + const contextText = "(@ to add context, / to switch modes" const imageText = shouldDisableImages ? "" : ", hold shift to drag in images" const helpText = imageText ? `\n${contextText}${imageText})` : `\n${contextText})` return baseText + helpText diff --git a/webview-ui/src/components/chat/ContextMenu.tsx b/webview-ui/src/components/chat/ContextMenu.tsx index 85ec865ccd..bd631a98d5 100644 --- a/webview-ui/src/components/chat/ContextMenu.tsx +++ b/webview-ui/src/components/chat/ContextMenu.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useMemo, useRef } from "react" import { ContextMenuOptionType, ContextMenuQueryItem, getContextMenuOptions } from "../../utils/context-mentions" import { removeLeadingNonAlphanumeric } from "../common/CodeAccordian" +import { ModeConfig } from "../../../../src/shared/modes" interface ContextMenuProps { onSelect: (type: ContextMenuOptionType, value?: string) => void @@ -10,6 +11,7 @@ interface ContextMenuProps { setSelectedIndex: (index: number) => void selectedType: ContextMenuOptionType | null queryItems: ContextMenuQueryItem[] + modes?: ModeConfig[] } const ContextMenu: React.FC = ({ @@ -20,12 +22,13 @@ const ContextMenu: React.FC = ({ setSelectedIndex, selectedType, queryItems, + modes, }) => { const menuRef = useRef(null) const filteredOptions = useMemo( - () => getContextMenuOptions(searchQuery, selectedType, queryItems), - [searchQuery, selectedType, queryItems], + () => getContextMenuOptions(searchQuery, selectedType, queryItems, modes), + [searchQuery, selectedType, queryItems, modes], ) useEffect(() => { @@ -46,6 +49,25 @@ const ContextMenu: React.FC = ({ const renderOptionContent = (option: ContextMenuQueryItem) => { switch (option.type) { + case ContextMenuOptionType.Mode: + return ( +
+ {option.label} + {option.description && ( + + {option.description} + + )} +
+ ) case ContextMenuOptionType.Problems: return Problems case ContextMenuOptionType.URL: @@ -101,6 +123,8 @@ const ContextMenu: React.FC = ({ const getIconForOption = (option: ContextMenuQueryItem): string => { switch (option.type) { + case ContextMenuOptionType.Mode: + return "symbol-misc" case ContextMenuOptionType.OpenedFile: return "window" case ContextMenuOptionType.File: @@ -174,15 +198,17 @@ const ContextMenu: React.FC = ({ overflow: "hidden", paddingTop: 0, }}> - + {option.type !== ContextMenuOptionType.Mode && getIconForOption(option) && ( + + )} {renderOptionContent(option)} {(option.type === ContextMenuOptionType.File || diff --git a/webview-ui/src/utils/context-mentions.ts b/webview-ui/src/utils/context-mentions.ts index 5cce936b28..0fb57071ab 100644 --- a/webview-ui/src/utils/context-mentions.ts +++ b/webview-ui/src/utils/context-mentions.ts @@ -1,11 +1,20 @@ import { mentionRegex } from "../../../src/shared/context-mentions" import { Fzf } from "fzf" +import { ModeConfig } from "../../../src/shared/modes" export function insertMention( text: string, position: number, value: string, ): { newValue: string; mentionIndex: number } { + // Handle slash command + if (text.startsWith("/")) { + return { + newValue: value, + mentionIndex: 0, + } + } + const beforeCursor = text.slice(0, position) const afterCursor = text.slice(position) @@ -55,6 +64,7 @@ export enum ContextMenuOptionType { URL = "url", Git = "git", NoResults = "noResults", + Mode = "mode", // Add mode type } export interface ContextMenuQueryItem { @@ -69,7 +79,42 @@ export function getContextMenuOptions( query: string, selectedType: ContextMenuOptionType | null = null, queryItems: ContextMenuQueryItem[], + modes?: ModeConfig[], ): ContextMenuQueryItem[] { + // Handle slash commands for modes + if (query.startsWith("/")) { + const modeQuery = query.slice(1) + if (!modes?.length) return [{ type: ContextMenuOptionType.NoResults }] + + // Create searchable strings array for fzf + const searchableItems = modes.map((mode) => ({ + original: mode, + searchStr: mode.name, + })) + + // Initialize fzf instance for fuzzy search + const fzf = new Fzf(searchableItems, { + selector: (item) => item.searchStr, + }) + + // Get fuzzy matching items + const matchingModes = modeQuery + ? fzf.find(modeQuery).map((result) => ({ + type: ContextMenuOptionType.Mode, + value: result.item.original.slug, + label: result.item.original.name, + description: result.item.original.roleDefinition.split("\n")[0], + })) + : modes.map((mode) => ({ + type: ContextMenuOptionType.Mode, + value: mode.slug, + label: mode.name, + description: mode.roleDefinition.split("\n")[0], + })) + + return matchingModes.length > 0 ? matchingModes : [{ type: ContextMenuOptionType.NoResults }] + } + const workingChanges: ContextMenuQueryItem = { type: ContextMenuOptionType.Git, value: "git-changes", @@ -203,6 +248,11 @@ export function getContextMenuOptions( } export function shouldShowContextMenu(text: string, position: number): boolean { + // Handle slash command + if (text.startsWith("/")) { + return position <= text.length && !text.includes(" ") + } + const beforeCursor = text.slice(0, position) const atIndex = beforeCursor.lastIndexOf("@") From f3bbf34a9072834a330f6a80f1c762cafbe5ae5c Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 5 Feb 2025 00:27:26 -0500 Subject: [PATCH 13/48] v3.3.11 --- .changeset/gorgeous-insects-punch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gorgeous-insects-punch.md diff --git a/.changeset/gorgeous-insects-punch.md b/.changeset/gorgeous-insects-punch.md new file mode 100644 index 0000000000..ce5300b3e8 --- /dev/null +++ b/.changeset/gorgeous-insects-punch.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +v3.3.11 From c32d3057d692a1435a456e37972c82d87de3d669 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Feb 2025 05:31:24 +0000 Subject: [PATCH 14/48] changeset version bump --- .changeset/gorgeous-insects-punch.md | 5 ----- .changeset/heavy-feet-judge.md | 5 ----- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) delete mode 100644 .changeset/gorgeous-insects-punch.md delete mode 100644 .changeset/heavy-feet-judge.md diff --git a/.changeset/gorgeous-insects-punch.md b/.changeset/gorgeous-insects-punch.md deleted file mode 100644 index ce5300b3e8..0000000000 --- a/.changeset/gorgeous-insects-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -v3.3.11 diff --git a/.changeset/heavy-feet-judge.md b/.changeset/heavy-feet-judge.md deleted file mode 100644 index b9b3ca0f7b..0000000000 --- a/.changeset/heavy-feet-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"roo-cline": patch ---- - -Safer shell profile path check diff --git a/CHANGELOG.md b/CHANGELOG.md index 983d2bfac4..4de56c4b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Roo Code Changelog +## 3.3.11 + +### Patch Changes + +- v3.3.11 +- Safer shell profile path check + ## [3.3.10] - Add shortcuts to the currently open tabs in the "Add File" section of @-mentions (thanks @olup!) diff --git a/package-lock.json b/package-lock.json index 2c518b330e..59949791f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "roo-cline", - "version": "3.3.10", + "version": "3.3.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "roo-cline", - "version": "3.3.10", + "version": "3.3.11", "dependencies": { "@anthropic-ai/bedrock-sdk": "^0.10.2", "@anthropic-ai/sdk": "^0.26.0", diff --git a/package.json b/package.json index 80528fdfd0..69d391a282 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Roo Code (prev. Roo Cline)", "description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.", "publisher": "RooVeterinaryInc", - "version": "3.3.10", + "version": "3.3.11", "icon": "assets/icons/rocket.png", "galleryBanner": { "color": "#617A91", From b5a8398d22d95fa04ab867d030e4d8d14836cff1 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 5 Feb 2025 00:34:24 -0500 Subject: [PATCH 15/48] Update CHANGELOG.md --- CHANGELOG.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de56c4b00..0a3bbfef82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,9 @@ # Roo Code Changelog -## 3.3.11 +## [3.3.11] -### Patch Changes - -- v3.3.11 -- Safer shell profile path check +- Safer shell profile path check to avoid an error on Windows +- Autocomplete for slash commands ## [3.3.10] From 4948e527793b13b6c1b5e3fecba9f9a737bc5f94 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 5 Feb 2025 00:51:59 -0800 Subject: [PATCH 16/48] Jest fixes for webview-ui --- webview-ui/jest.config.cjs | 22 +++++++++++ webview-ui/package.json | 39 ------------------- .../chat/__tests__/ChatTextArea.test.tsx | 1 - .../prompts/__tests__/PromptsView.test.tsx | 1 - .../__tests__/ApiConfigManager.test.tsx | 1 - 5 files changed, 22 insertions(+), 42 deletions(-) create mode 100644 webview-ui/jest.config.cjs diff --git a/webview-ui/jest.config.cjs b/webview-ui/jest.config.cjs new file mode 100644 index 0000000000..69ed93166e --- /dev/null +++ b/webview-ui/jest.config.cjs @@ -0,0 +1,22 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: "ts-jest", + testEnvironment: "jsdom", + injectGlobals: true, + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], + transform: { "^.+\\.(ts|tsx)$": ["ts-jest", { tsconfig: { jsx: "react-jsx" } }] }, + testMatch: ["/src/**/__tests__/**/*.{js,jsx,ts,tsx}", "/src/**/*.{spec,test}.{js,jsx,ts,tsx}"], + setupFilesAfterEnv: ["/src/setupTests.ts", "@testing-library/jest-dom/extend-expect"], + moduleNameMapper: { + "\\.(css|less|scss|sass)$": "identity-obj-proxy", + "^vscrui$": "/src/__mocks__/vscrui.ts", + "^@vscode/webview-ui-toolkit/react$": "/src/__mocks__/@vscode/webview-ui-toolkit/react.ts", + "^@/(.*)$": "/src/$1", + }, + reporters: [["jest-simple-dot-reporter", {}]], + transformIgnorePatterns: [ + "/node_modules/(?!(rehype-highlight|react-remark|unist-util-visit|unist-util-find-after|vfile|unified|bail|is-plain-obj|trough|vfile-message|unist-util-stringify-position|mdast-util-from-markdown|mdast-util-to-string|micromark|decode-named-character-reference|character-entities|markdown-table|zwitch|longest-streak|escape-string-regexp|unist-util-is|hast-util-to-text|@vscode/webview-ui-toolkit|@microsoft/fast-react-wrapper|@microsoft/fast-element|@microsoft/fast-foundation|@microsoft/fast-web-utilities|exenv-es6|vscrui)/)", + ], + roots: ["/src"], + moduleDirectories: ["node_modules", "src"], +} diff --git a/webview-ui/package.json b/webview-ui/package.json index 8229a6aa34..e3eb3c8818 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -69,44 +69,5 @@ "ts-jest": "^27.1.5", "typescript": "^4.9.5", "vite": "6.0.11" - }, - "jest": { - "testEnvironment": "jsdom", - "setupFilesAfterEnv": [ - "@testing-library/jest-dom/extend-expect" - ], - "preset": "ts-jest", - "reporters": [ - [ - "jest-simple-dot-reporter", - {} - ] - ], - "moduleNameMapper": { - "\\.(css|less|scss|sass)$": "identity-obj-proxy", - "^vscrui$": "/src/__mocks__/vscrui.ts", - "^@vscode/webview-ui-toolkit/react$": "/src/__mocks__/@vscode/webview-ui-toolkit/react.ts" - }, - "transformIgnorePatterns": [ - "/node_modules/(?!(rehype-highlight|react-remark|unist-util-visit|unist-util-find-after|vfile|unified|bail|is-plain-obj|trough|vfile-message|unist-util-stringify-position|mdast-util-from-markdown|mdast-util-to-string|micromark|decode-named-character-reference|character-entities|markdown-table|zwitch|longest-streak|escape-string-regexp|unist-util-is|hast-util-to-text|@vscode/webview-ui-toolkit|@microsoft/fast-react-wrapper|@microsoft/fast-element|@microsoft/fast-foundation|@microsoft/fast-web-utilities|exenv-es6|vscrui)/)" - ], - "transform": { - "^.+\\.(ts|tsx)$": [ - "ts-jest", - { - "tsconfig": { - "jsx": "react-jsx" - } - } - ] - }, - "moduleDirectories": [ - "node_modules", - "src" - ], - "testMatch": [ - "/src/**/__tests__/**/*.{js,jsx,ts,tsx}", - "/src/**/*.{spec,test}.{js,jsx,ts,tsx}" - ] } } diff --git a/webview-ui/src/components/chat/__tests__/ChatTextArea.test.tsx b/webview-ui/src/components/chat/__tests__/ChatTextArea.test.tsx index 599e8d3ddb..205912fc15 100644 --- a/webview-ui/src/components/chat/__tests__/ChatTextArea.test.tsx +++ b/webview-ui/src/components/chat/__tests__/ChatTextArea.test.tsx @@ -1,5 +1,4 @@ import { render, fireEvent, screen } from "@testing-library/react" -import "@testing-library/jest-dom" import ChatTextArea from "../ChatTextArea" import { useExtensionState } from "../../../context/ExtensionStateContext" import { vscode } from "../../../utils/vscode" diff --git a/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx b/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx index b31e0f868b..d3827a24c0 100644 --- a/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx +++ b/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx @@ -1,5 +1,4 @@ import { render, screen, fireEvent, waitFor } from "@testing-library/react" -import "@testing-library/jest-dom" import PromptsView from "../PromptsView" import { ExtensionStateContext } from "../../../context/ExtensionStateContext" import { vscode } from "../../../utils/vscode" diff --git a/webview-ui/src/components/settings/__tests__/ApiConfigManager.test.tsx b/webview-ui/src/components/settings/__tests__/ApiConfigManager.test.tsx index 7df9ea54ba..ac6245d6d1 100644 --- a/webview-ui/src/components/settings/__tests__/ApiConfigManager.test.tsx +++ b/webview-ui/src/components/settings/__tests__/ApiConfigManager.test.tsx @@ -1,5 +1,4 @@ import { render, screen, fireEvent } from "@testing-library/react" -import "@testing-library/jest-dom" import ApiConfigManager from "../ApiConfigManager" // Mock VSCode components From 98c8cc9624c9a796e1a22e428ee40101599259cc Mon Sep 17 00:00:00 2001 From: Nissa Seru <119150866+nissa-seru@users.noreply.github.com> Date: Wed, 5 Feb 2025 04:53:21 -0500 Subject: [PATCH 17/48] Updated sliding window logic to be inverse of trigger criteria --- src/core/sliding-window/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index 9e98ba17d7..ee4a1543e7 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -89,9 +89,9 @@ function getMaxTokensForNonPromptCachingModels(modelInfo: ModelInfo): number { /** * Provides the fraction of messages to remove for models that do not support prompt caching. * - * @param {ModelInfo} modelInfo - The model information (unused in current implementation). + * @param {ModelInfo} modelInfo - The model information. * @returns {number} The truncation fraction for non-prompt caching models (fixed at 0.1). */ function getTruncFractionForNonPromptCachingModels(modelInfo: ModelInfo): number { - return 0.1 + return Math.min(40_000 / modelInfo.contextWindow, 0.2) } From 1f492d5a16db9d2e125e6f669590ae91bcb98d91 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Wed, 5 Feb 2025 11:43:56 -0500 Subject: [PATCH 18/48] Revert "Don't change the actual mode when you view different mode configurations on the prompts tab" This reverts commit af0cd5b0fca5aeb30f639af4902499b6f20146b4. --- .../src/components/prompts/PromptsView.tsx | 72 +++++++++---------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index caef1cf94e..9d0aea6236 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -66,7 +66,6 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { const [isToolsEditMode, setIsToolsEditMode] = useState(false) const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false) const [activeSupportTab, setActiveSupportTab] = useState("ENHANCE") - const [selectedModeTab, setSelectedModeTab] = useState(mode) // Direct update functions const updateAgentPrompt = useCallback( @@ -112,23 +111,26 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { text: slug, }) }, []) - // Handle mode tab selection without actually switching modes + + // Handle mode switching with explicit state initialization const handleModeSwitch = useCallback( (modeConfig: ModeConfig) => { - if (modeConfig.slug === selectedModeTab) return // Prevent unnecessary updates + if (modeConfig.slug === mode) return // Prevent unnecessary updates - // Update selected tab and reset tools edit mode - setSelectedModeTab(modeConfig.slug) + // First switch the mode + switchMode(modeConfig.slug) + + // Exit tools edit mode when switching modes setIsToolsEditMode(false) }, - [selectedModeTab, setIsToolsEditMode], + [mode, switchMode, setIsToolsEditMode], ) // Helper function to get current mode's config const getCurrentMode = useCallback((): ModeConfig | undefined => { - const findMode = (m: ModeConfig): boolean => m.slug === selectedModeTab + const findMode = (m: ModeConfig): boolean => m.slug === mode return customModes?.find(findMode) || modes.find(findMode) - }, [selectedModeTab, customModes, modes]) + }, [mode, customModes, modes]) // Helper function to safely access mode properties const getModeProperty = ( @@ -154,11 +156,6 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { } }, [isCreateModeDialogOpen]) - // Keep selected tab in sync with actual mode - useEffect(() => { - setSelectedModeTab(mode) - }, [mode]) - // Helper function to generate a unique slug from a name const generateSlug = useCallback((name: string, attempt = 0): string => { const baseSlug = name @@ -188,6 +185,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { groups: newModeGroups, } updateCustomMode(newModeSlug, newMode) + switchMode(newModeSlug) setIsCreateModeDialogOpen(false) setNewModeName("") setNewModeSlug("") @@ -478,7 +476,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { padding: "4px 0", }}> {modes.map((modeConfig) => { - const isActive = selectedModeTab === modeConfig.slug + const isActive = mode === modeConfig.slug return ( + + + + + + No framework found. + + {frameworks.map((framework) => ( + { + setValue(currentValue === value ? "" : currentValue) + setOpen(false) + }}> + {framework.label} + + + ))} + + + + + + ) +} From 9b4a9391ee90ae2d1c224439ffaf5b6d171565b5 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Thu, 6 Feb 2025 23:03:25 -0500 Subject: [PATCH 47/48] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03a3ecafb9..134fb53c66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## [3.3.14] -- Should have skipped floor 13 like an elevator. Hopefully this fixes the broken 3.3.13 release by reverting some internal changes to the code structure 🙏 +- Should have skipped floor 13 like an elevator. This fixes the broken 3.3.13 release by reverting some changes to the deployment scripts. ## [3.3.13] From 483feabb156d0dd049aaf40b64c103b2f3a60271 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Fri, 7 Feb 2025 01:10:05 -0500 Subject: [PATCH 48/48] Update CHANGELOG.md Oops, left out a few things in 3.3.12. Sorry! --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 134fb53c66..b3b6309797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ ## [3.3.13] - Ensure the DeepSeek r1 model works with Ollama (thanks @sammcj!) +- Enable context menu commands in the terminal (thanks @samhvw8!) +- Improve sliding window truncation strategy for models that do not support prompt caching (thanks @nissa-seru!) - First step of a more fundamental fix to the bugs around switching API profiles. If you've been having issues with this please try again and let us know if works any better! More to come soon, including fixing the laggy text entry in provider settings. ## [3.3.12]