Compare commits

...

40 Commits

Author SHA1 Message Date
abeatrix 6ffba23d3d refactor: convert GitCommitGenerator from module to class
- Convert module pattern to class-based implementation
- Move abort controller to private instance variable
- Add proper method documentation with JSDoc
- Improve encapsulation and code organization
2025-09-02 14:24:11 -07:00
Bee b3abbd886e Update PostHog config to use dev environment in CI (#5954)
Add CI environment check to PostHog configuration logic to ensure
dev environment is used in both CI and local development contexts
2025-09-02 13:37:21 -07:00
Ara 8cdc4a936d Remove Shortcut of Cline from its title (#5952) 2025-09-02 13:14:54 -07:00
Nick Baumann ecc58178dc Jetbrains docs (#5948)
* docs: Update Claude Code documentation to include Pro plans alongside Max plans

* Add JetBrains installation documentation

- Create comprehensive installation guide for JetBrains IDEs
- Include both marketplace and manual installation methods
- Document supported IDEs and key differences from VSCode
- Add alpha status note and terminal integration limitations
- Update docs.json navigation to include new page

* Add images to JetBrains installation documentation

- Add demo GIF showing Cline in action in JetBrains IDE
- Add screenshot of JetBrains marketplace download page
- Add screenshot of Install Plugin from Disk dialog
- Add screenshot of file selection dialog with zip file
- Complete visual walkthrough of installation process

* Update JetBrains demo to high-quality GIF

- Replace jetbrains-demo.gif with jetbrains-demo-hifi.gif
- Improved visual quality for better user experience

* Add JetBrains settings dialog screenshot

- Add screenshot showing the main settings dialog
- Provides visual guidance for accessing IDE settings
- Complete visual walkthrough now includes 5 screenshots

* Add JetBrains logo and finalize documentation

- Add JetBrains logo at top of page with proper styling
- Update content with user revisions (BYOK note, streamlined structure)
- Complete visual installation walkthrough with 5 images
- Ready for PR review
2025-09-02 12:45:31 -07:00
celestial-vault ca3f0f1abd don't delete old location of taskHistory in migration for now (#5931) 2025-09-02 11:21:53 -07:00
celestial-vault 987812a886 add taskHistory size fetch after deleting all tasks to refresh size displayed (#5932) 2025-09-02 11:21:24 -07:00
Sarah Fortune 0e6afd9848 Add the OS name and version to the telemetry metadata (#5946)
Add the OS name and version to the telemetry metadata properties.
Update the test.
2025-09-02 10:52:40 -07:00
Bee 359e0e070d fix: use retry functionality for failed API requests and disable send btn (#5892)
- Add "retry" action type to ButtonActionType
- Update api_req_failed button config to use retry action with disabled sending
- Implement retry handler in useMessageHandlers to send simple approval and clear input state
2025-09-02 10:17:04 -07:00
Sarah Fortune b02ad8377d Add the host IDE metadata to the telemetry events (#5945)
Add properties to the telemetry events for the host environment name and version.

Add a .create() function to the TelemetryService because we can't use async in the constructor. (Getting the host platform version is async).
2025-09-02 09:21:18 -07:00
Sarah Fortune 8fdf5ab8c5 Fix bug in distinctId (#5943)
getMachineId was not returning the correct value and a new distint ID was getting generated every time the extension started.

Add tests and logging for distinctId.ts
2025-09-02 08:37:30 -07:00
Ara aceaeb069b Fixing failing webview test (#5933)
* Fixing failing webview test

* Fixing failing webview test
2025-09-01 16:22:35 -07:00
celestial-vault e39e58b5e2 add no unused imports error (#5911) 2025-09-01 15:44:38 -07:00
Saoud Rizwan 717be3f026 Fix grok-code-fast-1 model information and add promo in Announcement banner (#5926)
* Fix grok-code-fast-1 info

* Add call to action for trying free `grok-code-fast-1` in Announcement banner
2025-09-01 05:41:18 -07:00
Saoud Rizwan 5595d12dc3 fix (templated system prompt): add TASK_PROGRESS_PARAMETER to various tools and update descriptions (#5908)
* Add TASK_PROGRESS_PARAMETER to various tools and update descriptions

- Introduced TASK_PROGRESS_PARAMETER to enhance task tracking across multiple tools.
- Updated tool descriptions for clarity and consistency, including detailed instructions and usage examples.
- Adjusted existing parameters to improve user guidance and ensure proper tool functionality.

* update snapshots

* do not remove new lines within section around divider

---------

Co-authored-by: abeatrix <beatrix@cline.bot>
2025-08-30 22:41:24 -07:00
Saoud Rizwan c230de0a14 Disable buttons immediately after click (#5902) 2025-08-30 11:53:26 -07:00
celestial-vault 2ecb87ac5a Move task history to file storage (#5877)
* Move task history to file storage

* add console logs to migration

* update code comment
2025-08-30 10:45:31 -07:00
Saoud Rizwan 2315fc6769 Fix write_to_file tool diff streaming, discrepencies with original tool execution, attempt_completion command issue, and input not clearing when hitting approve (#5903)
* Fix write_to_file tool diff streaming

* Fix discrepencies with original tool execution logic

* Fix attempt completion command leading to 'ask promise was ignored' error

* Fix input not being cleared when hitting approve button
2025-08-30 06:15:09 -07:00
Ara 6449c36849 Revert "Adding frequency penalty for gemini models (#5893)" (#5898)
This reverts commit 10cfd8ba1e.
2025-08-30 00:35:36 -07:00
Saoud Rizwan 8f93e9cc40 Fix browser session not being persisted between browser tool calls (#5901) 2025-08-30 00:21:32 -07:00
Saoud Rizwan 3a52baac14 Fix ToolExecutor refactor issue where user feedback for tool use is ignored (#5899)
* Fix ToolExecutor refactor issue where user feedback for tool use is ignored

* Deduplicate code

* Fix merge conflicts
2025-08-30 00:18:54 -07:00
Tomás Barreiro 35f08731f6 fix: Improve Gemini Rate Limit handling (#5205)
* Pass all options to the handlers

* Do not pass all options

* Have onRetryAttempt as a common option

* Update the Gemini CLI

* Throw a RetriableError and extract retry delays from the error responses

* Add changeset

* Throw a RetriableError if extracting the delay fails

* Improve parseRetryDelay

* Add fallback
2025-08-29 20:58:04 -07:00
Bee 2c866c9265 Refactor posthog service providers and centralize distinct ID management (#5705)
* Refactor services architecture with provider pattern and factory classes

- Extract telemetry, error handling, and feature flags into separate service modules
- Implement provider pattern with factory classes for better abstraction
- Move PostHog-specific implementations to dedicated provider classes
- Add interfaces for telemetry, error, and feature flags providers
- Update imports across codebase to use new service structure
- Add unit tests for telemetry service

* Refactor service providers and centralize distinct ID management

- Move provider interfaces to dedicated providers/ subdirectories
- Extract distinct ID management to shared logging/distinctId module
- Simplify PostHogClientProvider by removing distinct ID parameter
- Update service factories to use centralized distinct ID
- Reorganize test files to __tests__/ directories
- Remove redundant distinct ID handling across services

* merge main

* clean up

* add grok coder free model to cline provider (#5808)

* add free grok-coder-free model to cline provider

* add changeset

* fix typo

* v3.26.6 Release Notes (#5788)

* changeset version bump

* Updating CHANGELOG.md format

* Update CHANGELOG.md for version 3.26.6 with user-friendly descriptions

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: pashpashpash <nik@cline.bot>

* Remove top padding from ActionButtons component (#5806)

Eliminate unnecessary top padding in the chat view.

* removing middle out from params to or / cline providers (#5811)

* Dify.ai integration (#5761)

* add focus chain settings to statemanager initialize function (#5798)

* add custom gpt-5 system prompt (#5757)

* gpt-5 system prompt

* add changeset

* Focus chain telemetry tweaks (#5810)

Co-authored-by: Kevin Bond <kevin@Kevins-MacBook-Pro.local>

* Remove eslint-rules test patterns from Mocha spec configuration (#5812)

Update the "spec" array in .mocharc.json to exclude "eslint-rules/__tests__/**/*.test.ts",
as that directory has been removed.

* Increase horizontal margin in AutoApproveBar component (#5813)

Update the mx-[5px] to mx-[15px] in the div's className to adjust horizontal spacing for improved layout alignment.

* fix: remove hardcoded Ollama host from options (#5816)

* fix: remove hardcoded Ollama host from options

Updates the Ollama handler to remove the hardcoded "http://localhost:11434" as the `ollamaBaseUrl` fallback option for the host to allow the Ollama SDK to handle the default endpoint configured on users' machine.

Reason: Ollama allows cross-origin requests from 127.0.0.1 and 0.0.0.0 by default. However, when we use localhost, the browser would resolve it through DNS, which can result in different IP addresses.

Docs: https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-expose-ollama-on-my-network

* add changeset

* deep-planning prompt PowerShell (#5699)

* Windows/Powershell specific deep planning prompt changes

* Prompt adjustments

---------

Co-authored-by: Kevin Bond <kevin@Kevins-MacBook-Pro.local>

* Changes to condenseToolResponse & summarizeTask prompting (#5817)

* Condense & deep planning prompt adjustments

* Removed ps prompting ready for PR

* rebase

* Fixed typo on one word

---------

Co-authored-by: Kevin Bond <kevin@Kevins-MacBook-Pro.local>

* rename CacheService to StateManager (#5681)

* rename CacheService to StateManager

* fix types

* infer state key types from existing interfaces (#5815)

* fix: AutoApproveModal positioning and scrolling behavior (#5819)

* fix: AutoApproveModal positioning and scrolling behavior

- Add dynamic positioning calculation to prevent modal overflow
- Implement proper flex layout with scrollable content container
- Ensure minimum usable height and top margin constraints
- Fix modal positioning when button is near viewport edges

* Add changeset

* clean up

* template-based system prompt (#5731)

* Refactor system prompt architecture with new template-based system

- Move existing system prompt files to legacy directory
- Implement new modular system with PromptBuilder, PromptRegistry, and TemplateEngine
- Add component-based prompt structure with reusable parts (capabilities, rules, tool_use, etc.)
- Create variant-specific templates for generic and next-gen models
- Add comprehensive test suite with snapshots for different model configurations
- Introduce template engine with placeholder support for dynamic prompt generation

* Refactor system prompt architecture with modular tool definitions

- Extract tool specifications into dedicated modules under tools/
- Add ClineToolSet class for managing tool variants by model family
- Restructure prompt components with centralized index exports
- Update prompt builder and registry to support new tool architecture
- Reorganize shared utilities and type definitions
- Update all test snapshots to reflect new prompt structure

* Update snapshots

* reorg

* Update template format

* clean up

* typos

* focus chain section

* fix task progress in attempt_completion

* Implement tool retrieval with fallback options in PromptBuilder

- Added `getToolByNameWithFallback` and `getToolsForVariantWithFallback` methods to `ClineToolSet` for improved tool resolution.
- Updated `getToolsPrompts` in `PromptBuilder` to utilize these new methods, allowing for better handling of tool requests with fallback to generic tools.
- Enhanced sorting and filtering of tools based on context requirements and requested order.

* update fild structure

* clean up

* fix static test string

* Update snapshot names

* Update unit test

* Remove unused placeholders and update docs

* Update README on how to add new tool

* Remove task_progress reference from attempt_completion tool description when focus chain is disabled

* Upgrade posthog-node to v5.8.0 and add exception filtering

- Update posthog-node from v4.8.1 to v5.8.0
- Add EventMessage import for type safety
- Implement posthogEventFilter to only capture exceptions from Cline extension
- Filter exceptions by checking for "cline" in error messages or "saoudrizwan" in stack frames

* Use env var keys

- Add PostHogClientConfig to ErrorProviderFactory with proper validation
- Update PostHogErrorProvider to use dedicated client instead of shared one
- Add API key validation in PostHogFeatureFlagsProvider before client creation
- Enhance error handling with fallback to NoOpErrorProvider instead of throwing
- Standardize configuration passing across telemetry, error, and feature flag services

* Upadte filter

* update filter

* update imports

* use secret

* disable enableExceptionAutocapture

* removes vscode.env.machineId

* initializeDistinctId

* use get trap as workaround

* on exit

---------

Co-authored-by: pashpashpash <nik@cline.bot>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Toshii <94262432+0xToshii@users.noreply.github.com>
Co-authored-by: Yunus Emre AYHAN <ayhanyunusemre@gmail.com>
Co-authored-by: celestial-vault <58194240+celestial-vault@users.noreply.github.com>
Co-authored-by: canvrno <46584286+canvrno@users.noreply.github.com>
Co-authored-by: Kevin Bond <kevin@Kevins-MacBook-Pro.local>
2025-08-29 18:27:35 -07:00
Ara 10cfd8ba1e Adding frequency penalty for gemini models (#5893)
* Adding frequency penalty for gemini models

* Adding frequency penalty for gemini models

* Adding frequency penalty for gemini models

* Adding frequency penalty for gemini models

* Adding frequency penalty for gemini models
2025-08-29 17:24:38 -07:00
Saoud Rizwan da4d88fd84 hotfix: Add 200k context window variant for Claude Sonnet 4 to OpenRouter and Cline providers (#5894)
* Add 200k context window variant for Claude Sonnet 4 to OpenRouter and Cline providers

* v3.26.7 Release Notes
2025-08-29 16:56:50 -07:00
celestial-vault 889ed95840 fix z index mcp response dropdown (#5882) 2025-08-29 12:48:01 -07:00
Toshii 716e6cd6ab changing prompts for the context management (#5854)
* changing prompts for the context management

* distinction between the tool call options
2025-08-29 12:22:48 -07:00
Bee 45871a962e fix: improve caching and prevent duplicate fetches in AccountView (#5883)
* fix:  improve caching and prevent duplicate fetches in AccountView

- Wrap cacheCurrentData in useCallback with proper dependencies
- Add initialFetchCompleteRef to track mount fetch completion
- Improve organization change handling to prevent race conditions
- Remove biome-ignore comments for exhaustive dependencies
- Replace mb-[5px] with mb-1.5 for consistent Tailwind spacing

* changeset added
2025-08-29 11:18:55 -07:00
Sarah Fortune c6aa47095e Fix int32 overflow in the models proto (#5881)
Cline-core is setting some of these values in the models proto to the javascript Number.MAX_SAFE_VALUE, which won't fit in int32, so these protobuf messages fail to serialize to and can't be transported.

Just change all the int32s in this file to int64 beceause this is the second time this same issue has occured.

Fixes:
```
2025-08-28 16:30:03,824 [   3479]   WARN - bot.cline.services.ProtoBusProxyService - Stream cline.ModelsService.subscribeToOpenRouterModels encountered error
io.grpc.StatusException: INTERNAL: invalid int32: 9007199254740991
        at io.grpc.Status.asException(Status.java:548)
        at io.grpc.kotlin.ClientCalls$rpcImpl$1$1$1.onClose(ClientCalls.kt:300)
        at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:564)
        at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:72)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:729)
        at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:710)
        at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
        at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Wor
```
2025-08-28 18:44:56 -07:00
Bee 8c1093cfdc add health checks and generic fallback to PromptRegistry (#5879)
* fix: Harden PromptRegistry with health checks and generic fallback

- Perform registry health check after loading (validate GENERIC, log counts/warnings)
- Always try GENERIC when family-specific variant is missing
- Enhance error diagnostics with available variants and registry state
- Ensure GENERIC variant exists; create minimal fallback if loading fails
- Minor test style cleanup and variants index update to support reliability

* simpilfy

* variants

* Fix import

* type safe

* remove lazy loading

* load and set variants

* fix import location
2025-08-28 16:39:56 -07:00
Saoud Rizwan 31161f894b Add search functionality to API provider dropdown (#5801)
* Add search functionality to API provider dropdown

* Create heavy-dolls-cry.md

* Remove unnecessary comments

* Remove unncessary comments

* Fix e2e tests checking API provide functionality

* Add Dify.ai provider

* Fix merge conflict
2025-08-28 13:32:45 -07:00
Sarah Fortune 20e5ae7b23 Don't throw an exception if deleting a directory fails. (#5868)
* Don't throw an exception if deleting a directory fails.

* Apply suggestion from @ellipsis-dev[bot]

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-08-28 13:08:33 -07:00
Toshii 22f306e79e default state for useCondense set to false (#5869) 2025-08-28 13:03:01 -07:00
Saoud Rizwan 553b56336c Update copy in README (#5871) 2025-08-28 12:23:38 -07:00
Saoud Rizwan a3fa8cf7b9 Revert "Modify workflow to publish to release to OVSX"
This reverts commit 3d5605f5d7.
2025-08-28 12:08:16 -07:00
Tomás Barreiro 4628eca3dc fix: Support Anthropic Prompt Caching when using LiteLLM (#5833)
* fix: Support Anthropic cache with LiteLLM

* Add changeset

* Fix and expand tests
2025-08-28 19:23:27 +02:00
yuvalman 518e624086 fix: sap provider - show models when resource group field is empty (and use the default value) (#5839)
* fix: sap provider - show models when resource group field is empty

* fix: sap provider - show models when resource group field is empty

* fix: sap provider - show models when resource group field is empty
2025-08-28 10:12:50 -07:00
kvyb fa4fa01ec3 feat: add openClineSidebarPanel RPC and route VS Code focus via hostbridge (#5859) 2025-08-28 19:38:19 +03:00
Toshii f526317796 swapping order of checkpoint and tool result (#5853) 2025-08-27 23:51:53 -07:00
Will Hardwick-Smith 550883df6a bugfix: fixes issue where thinking output wasn't passed through from (#5852)
litellm
2025-08-27 22:25:14 -07:00
Saoud Rizwan 3d5605f5d7 Modify workflow to publish to release to OVSX 2025-08-27 19:38:23 -07:00
162 changed files with 4695 additions and 2112 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
fix showing the ai core exisiting models when resource group field is empty (using the default resource group)
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Fix issue on Account view where balance is fetched twice that cause janky UI
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Fixes an issue where thinking text from litellm was not being passed through to Cline thinking UI
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Add search functionality to API provider dropdown
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
Improve Gemini Rate Limit handling
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
fix: Support Anthropic Caching when using LiteLLM
+2 -1
View File
@@ -10,5 +10,6 @@
"source-map-support/register",
"./src/test/requires.ts"
],
"recursive": true
"recursive": true,
"exit": true
}
+9
View File
@@ -1,5 +1,14 @@
# Changelog
## [3.27.0]
- Fix `grok-code-fast-1` model information
- Add call to action for trying free `grok-code-fast-1` in Announcement banner
## [3.26.7]
- Add 200k context window variant for Claude Sonnet 4 to OpenRouter and Cline providers
## [3.26.6]
- Add free Grok Coder model to Cline provider for users looking for a fast, free coding model option
+3 -3
View File
@@ -30,9 +30,9 @@ English | <a href="https://github.com/cline/cline/blob/main/locales/es/README.md
</table>
</div>
Meet Cline (pronounced /klaɪn/, like "Klein"), an AI assistant that can use your **CLI** a**N**d **E**ditor.
Meet Cline, an AI assistant that can use your **CLI** a**N**d **E**ditor.
Thanks to [Claude 3.7 Sonnet's agentic coding capabilities](https://www.anthropic.com/claude/sonnet), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
Thanks to [Claude Sonnet's agentic coding capabilities](https://www.anthropic.com/claude/sonnet), Cline can handle complex software development tasks step-by-step. With tools that let him create & edit files, explore large projects, use the browser, and execute terminal commands (after you grant permission), he can assist you in ways that go beyond code completion or tech support. Cline can even use the Model Context Protocol (MCP) to create new tools and extend his own capabilities. While autonomous AI scripts traditionally run in sandboxed environments, this extension provides a human-in-the-loop GUI to approve every file change and terminal command, providing a safe and accessible way to explore the potential of agentic AI.
1. Enter your task and add images to convert mockups into functional apps or fix bugs with screenshots.
2. Cline starts by analyzing your file structure & source code ASTs, running regex searches, and reading relevant files to get up to speed in existing projects. By carefully managing what information is added to context, Cline can provide valuable assistance even for large, complex projects without overwhelming the context window.
@@ -87,7 +87,7 @@ All changes made by Cline are recorded in your file's Timeline, providing an eas
### Use the Browser
With Claude 3.5 Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
With Claude Sonnet's new [Computer Use](https://www.anthropic.com/news/3-5-models-and-computer-use) capability, Cline can launch a browser, click elements, type text, and scroll, capturing screenshots and console logs at each step. This allows for interactive debugging, end-to-end testing, and even general web use! This gives him autonomy to fixing visual bugs and runtime issues without you needing to handhold and copy-pasting error logs yourself.
Try asking Cline to "test the app", and watch as he runs a command like `npm run dev`, launches your locally running dev server in a browser, and performs a series of tests to confirm that everything works. [See a demo here.](https://x.com/sdrzn/status/1850880547825823989)
+2 -1
View File
@@ -37,7 +37,8 @@
"useYield": "off",
"noConstructorReturn": "off",
"noInvalidPositionAtImportRule": "off",
"noSwitchDeclarations": "off"
"noSwitchDeclarations": "off",
"noUnusedImports": "error"
},
"a11y": "off",
"style": {
+1
View File
@@ -60,6 +60,7 @@
"getting-started/what-is-cline",
"getting-started/model-selection-guide",
"getting-started/installing-cline",
"getting-started/installing-cline-jetbrains",
"getting-started/task-management",
"getting-started/understanding-context-management",
{
@@ -0,0 +1,135 @@
---
title: "Installing Cline for JetBrains"
description: "Get Cline running in your favorite JetBrains IDE with the same powerful AI assistance you know from VSCode."
---
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/jetbrains-logo.svg"
alt="JetBrains logo"
style={{ width: "200px", height: "auto", margin: "0 auto 20px auto", display: "block" }}
/>
</Frame>
Cline for JetBrains works almost identically to Cline in VSCode. All the core features work properly: diff editing, using tools, logging in with different providers, MCP servers, Cline rules and workflows, and more.
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/jetbrains-demo-hifi.gif"
alt="Cline running in JetBrains IDE showing AI assistance"
/>
</Frame>
<Note>Cline for JetBrains is currently in alpha. While all core features are functional, you may encounter occasional issues.</Note>
## Installation
Since Cline for JetBrains is currently in alpha, it's not yet available on the JetBrains Marketplace. You'll need to install it manually from a downloaded file:
### Manual Installation from Disk
1. **Download the Plugin:**
- Go to [https://plugins.jetbrains.com/plugin/28247-cline/versions/stable](https://plugins.jetbrains.com/plugin/28247-cline/versions/stable)
- Click **Download** to get the `.zip` file
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/cline-jetbrains-marketplace-download.png"
alt="JetBrains plugin marketplace showing Cline download page"
/>
</Frame>
2. **Install from Disk:**
- Open your JetBrains IDE
- Go to **IntelliJ IDEA** (or whichever IDE you are in) → **Settings**
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/cline-jetbrains-settings.png"
alt="JetBrains IDE settings dialog"
/>
</Frame>
- Select **Plugins** from the left sidebar
- Click the gear icon ⚙️ and select **Install Plugin from Disk...**
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/cline-jetbrains-install-disk.png"
alt="JetBrains IDE settings showing Install Plugin from Disk option"
/>
</Frame>
- Select the downloaded `.zip` file
<Frame>
<img
src="https://storage.googleapis.com/cline_public_images/docs/assets/cline-jetbrains-zip-file.png"
alt="File selection dialog showing Cline plugin zip file"
/>
</Frame>
- Restart your IDE when prompted
## Getting Started with Cline
After installation, you'll find Cline in your IDE:
1. **Open Cline:**
- Look for the Cline tool window (usually on the right side)
- Or go to **View** → **Tool Windows** → **Cline**
2. **Sign In (optional, BYOK is also available):**
- Click **Sign In** in the Cline panel
- You'll be taken to [app.cline.bot](https://app.cline.bot) to create your account
- No credit card needed to get started with free credits
3. **Start Coding:**
- Try this first prompt: "Hey Cline! Can you help me create a simple Hello World program in this project?"
## Key Differences from VSCode
While Cline for JetBrains includes all the same powerful features, there's one important difference to be aware of:
**Terminal Integration:** The terminal inside JetBrains isn't integrated with Cline the same way it is in VSCode. Cline can execute commands, but the output will only appear in the webview if you expand the **Command Output** section.
This means:
- Commands still run successfully
- You can see the output by clicking to expand Command Output in the chat
- Terminal commands work the same way, just with a different display
## What Works
Everything else works exactly like VSCode:
- **Diff Editing:** Cline can read, write, and edit files with the same precision
- **Tool Usage:** All of Cline's tools (file operations, web browsing, etc.) work identically
- **API Providers:** Connect to Anthropic, OpenAI, local models, and more
- **MCP Servers:** Full support for Model Context Protocol servers
- **Cline Rules:** Custom instructions and workflows work the same way
- **@ Mentions:** Reference files, folders, problems, and more
- **Drag & Drop:** Add files and images to conversations
## Tips for JetBrains Users
- **Project Context:** Cline automatically understands your project structure, just like in VSCode
- **Language Support:** Cline works with any language your JetBrains IDE supports
- **Debugging Help:** Share error messages and stack traces directly in the chat
- **Code Review:** Ask Cline to review your code changes before committing
## Troubleshooting
If you don't see the Cline tool window after installation:
- Restart your IDE completely
- Check **View** → **Tool Windows** → **Cline**
- Ensure the plugin is enabled in **Settings** → **Plugins**
Having other issues? Join our [Discord community](https://discord.gg/cline) for help from the team and other users.
## Next Steps
Now that you have Cline installed, you might want to:
- Learn about [model selection](/getting-started/model-selection-guide) to choose the best AI provider
- Explore [@ mentions](/features/at-mentions/overview) to reference files and context efficiently
- Set up [Cline rules](/features/cline-rules) for your specific workflow
- Try [MCP servers](/mcp/mcp-overview) to extend Cline's capabilities
+25 -12
View File
@@ -1,12 +1,12 @@
{
"name": "claude-dev",
"version": "3.26.6",
"version": "3.27.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claude-dev",
"version": "3.26.6",
"version": "3.27.0",
"license": "Apache-2.0",
"dependencies": {
"@anthropic-ai/sdk": "^0.37.0",
@@ -16,7 +16,7 @@
"@bufbuild/protobuf": "^2.2.5",
"@cerebras/cerebras_cloud_sdk": "^1.35.0",
"@google-cloud/vertexai": "^1.9.3",
"@google/genai": "1.0.0",
"@google/genai": "^1.11.0",
"@grpc/grpc-js": "^1.9.15",
"@grpc/reflection": "^1.0.4",
"@mistralai/mistralai": "^1.5.0",
@@ -66,7 +66,7 @@
"p-timeout": "^6.1.4",
"p-wait-for": "^5.0.2",
"pdf-parse": "^1.1.1",
"posthog-node": "^4.8.1",
"posthog-node": "^5.8.0",
"puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0",
"reconnecting-eventsource": "^1.6.4",
@@ -2531,19 +2531,24 @@
}
},
"node_modules/@google/genai": {
"version": "1.0.0",
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.15.0.tgz",
"integrity": "sha512-4CSW+hRTESWl3xVtde7pkQ3E+dDFhDq+m4ztmccRctZfx1gKy3v0M9STIMGk6Nq0s6O2uKMXupOZQ1JGorXVwQ==",
"license": "Apache-2.0",
"dependencies": {
"google-auth-library": "^9.14.2",
"ws": "^8.18.0",
"zod": "^3.22.4",
"zod-to-json-schema": "^3.22.4"
"ws": "^8.18.0"
},
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
},
"peerDependencies": {
"@modelcontextprotocol/sdk": "^1.11.0"
},
"peerDependenciesMeta": {
"@modelcontextprotocol/sdk": {
"optional": true
}
}
},
"node_modules/@grpc/grpc-js": {
@@ -3685,6 +3690,12 @@
"node": ">=18"
}
},
"node_modules/@posthog/core": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.0.1.tgz",
"integrity": "sha512-bwXUeHe+MLgENm8+/FxEbiNocOw1Vjewmm+HEUaYQe6frq8OhZnrvtnzZU3Q3DF6N0UbAmD/q+iNfNgyx8mozg==",
"license": "MIT"
},
"node_modules/@protobufjs/aspromise": {
"version": "1.1.2",
"license": "BSD-3-Clause"
@@ -12387,13 +12398,15 @@
}
},
"node_modules/posthog-node": {
"version": "4.8.1",
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.8.0.tgz",
"integrity": "sha512-Idj6TgjYN0POXvrGK97ZKTLbLEY7sUjsaeMaquKt9UlK3Z9ps0nj0wRkFYKEYvfQ8OMwTwgKaze+5hXgmudwdw==",
"license": "MIT",
"dependencies": {
"axios": "^1.7.4"
"@posthog/core": "1.0.1"
},
"engines": {
"node": ">=15.0.0"
"node": ">=20"
}
},
"node_modules/prebuild-install": {
+5 -12
View File
@@ -2,7 +2,7 @@
"name": "claude-dev",
"displayName": "Cline",
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
"version": "3.26.6",
"version": "3.27.0",
"icon": "assets/icons/icon.png",
"engines": {
"vscode": "^1.84.0"
@@ -102,15 +102,8 @@
"activitybar": [
{
"id": "claude-dev-ActivityBar",
"title": "Cline (⌘+')",
"icon": "assets/icons/icon.svg",
"when": "isMac"
},
{
"id": "claude-dev-ActivityBar",
"title": "Cline (Ctrl+')",
"icon": "assets/icons/icon.svg",
"when": "!isMac"
"title": "Cline",
"icon": "assets/icons/icon.svg"
}
]
},
@@ -431,7 +424,7 @@
"@bufbuild/protobuf": "^2.2.5",
"@cerebras/cerebras_cloud_sdk": "^1.35.0",
"@google-cloud/vertexai": "^1.9.3",
"@google/genai": "1.0.0",
"@google/genai": "^1.11.0",
"@grpc/grpc-js": "^1.9.15",
"@grpc/reflection": "^1.0.4",
"@mistralai/mistralai": "^1.5.0",
@@ -479,7 +472,7 @@
"p-timeout": "^6.1.4",
"p-wait-for": "^5.0.2",
"pdf-parse": "^1.1.1",
"posthog-node": "^4.8.1",
"posthog-node": "^5.8.0",
"puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0",
"reconnecting-eventsource": "^1.6.4",
+12 -12
View File
@@ -50,20 +50,20 @@ message LanguageModelChatSelector {
// Price tier for tiered pricing models
message PriceTier {
int32 token_limit = 1; // Upper limit (inclusive) of input tokens for this price
int64 token_limit = 1; // Upper limit (inclusive) of input tokens for this price
double price = 2; // Price per million tokens for this tier
}
// Thinking configuration for models that support thinking/reasoning
message ThinkingConfig {
optional int32 max_budget = 1; // Max allowed thinking budget tokens
optional int64 max_budget = 1; // Max allowed thinking budget tokens
optional double output_price = 2; // Output price per million tokens when budget > 0
repeated PriceTier output_price_tiers = 3; // Optional: Tiered output price when budget > 0
}
// Model tier for tiered pricing structures
message ModelTier {
int32 context_window = 1;
int64 context_window = 1;
optional double input_price = 2;
optional double output_price = 3;
optional double cache_writes_price = 4;
@@ -161,8 +161,8 @@ enum ApiProvider {
// Model info for OpenAI-compatible models
message OpenAiCompatibleModelInfo {
optional int32 max_tokens = 1;
optional int32 context_window = 2;
optional int64 max_tokens = 1;
optional int64 context_window = 2;
optional bool supports_images = 3;
bool supports_prompt_cache = 4;
optional double input_price = 5;
@@ -179,8 +179,8 @@ message OpenAiCompatibleModelInfo {
// Model info for LiteLLM models
message LiteLLMModelInfo {
optional int32 max_tokens = 1;
optional int32 context_window = 2;
optional int64 max_tokens = 1;
optional int64 context_window = 2;
optional bool supports_images = 3;
bool supports_prompt_cache = 4;
optional double input_price = 5;
@@ -232,8 +232,8 @@ message ModelsApiConfiguration {
optional string requesty_base_url = 33;
optional string together_api_key = 34;
optional string fireworks_api_key = 35;
optional int32 fireworks_model_max_completion_tokens = 36;
optional int32 fireworks_model_max_tokens = 37;
optional int64 fireworks_model_max_completion_tokens = 36;
optional int64 fireworks_model_max_tokens = 37;
optional string qwen_api_key = 38;
optional string doubao_api_key = 39;
optional string mistral_api_key = 40;
@@ -245,7 +245,7 @@ message ModelsApiConfiguration {
optional string xai_api_key = 46;
optional string sambanova_api_key = 47;
optional string cerebras_api_key = 48;
optional int32 request_timeout_ms = 49;
optional int64 request_timeout_ms = 49;
optional string sap_ai_core_client_id = 50;
optional string sap_ai_core_client_secret = 51;
optional string sap_ai_resource_group = 52;
@@ -273,7 +273,7 @@ message ModelsApiConfiguration {
// Plan mode configurations
optional ApiProvider plan_mode_api_provider = 100;
optional string plan_mode_api_model_id = 101;
optional int32 plan_mode_thinking_budget_tokens = 102;
optional int64 plan_mode_thinking_budget_tokens = 102;
optional string plan_mode_reasoning_effort = 103;
optional LanguageModelChatSelector plan_mode_vs_code_lm_model_selector = 104;
optional bool plan_mode_aws_bedrock_custom_selected = 105;
@@ -305,7 +305,7 @@ message ModelsApiConfiguration {
// Act mode configurations
optional ApiProvider act_mode_api_provider = 200;
optional string act_mode_api_model_id = 201;
optional int32 act_mode_thinking_budget_tokens = 202;
optional int64 act_mode_thinking_budget_tokens = 202;
optional string act_mode_reasoning_effort = 203;
optional LanguageModelChatSelector act_mode_vs_code_lm_model_selector = 204;
optional bool act_mode_aws_bedrock_custom_selected = 205;
+7
View File
@@ -26,6 +26,9 @@ service WorkspaceService {
// Opens the IDE file explorer panel and selects a file or directory.
rpc openInFileExplorerPanel(OpenInFileExplorerPanelRequest) returns (OpenInFileExplorerPanelResponse);
// Opens and focuses the Cline sidebar panel in the host IDE.
rpc openClineSidebarPanel(OpenClineSidebarPanelRequest) returns (OpenClineSidebarPanelResponse);
}
message GetWorkspacePathsRequest {
@@ -86,3 +89,7 @@ message OpenInFileExplorerPanelRequest {
string path = 1;
}
message OpenInFileExplorerPanelResponse {}
// Request/response for opening the Cline sidebar
message OpenClineSidebarPanelRequest {}
message OpenClineSidebarPanelResponse {}
+17 -16
View File
@@ -1,19 +1,22 @@
import * as vscode from "vscode"
import {
migrateCustomInstructionsToGlobalRules,
migrateTaskHistoryToFile,
migrateWelcomeViewCompleted,
migrateWorkspaceToGlobalStorage,
} from "./core/storage/state-migrations"
import { WebviewProvider } from "./core/webview"
import { Logger } from "./services/logging/Logger"
import { PostHogClientProvider } from "./services/posthog/PostHogClientProvider"
import { EmptyRequest } from "./shared/proto/cline/common"
import { WebviewProviderType } from "./shared/webview/types"
import "./utils/path" // necessary to have access to String.prototype.toPosix
import { HostProvider } from "@/hosts/host-provider"
import { FileContextTracker } from "./core/context/context-tracking/FileContextTracker"
import { telemetryService } from "./services/posthog/PostHogClientProvider"
import { errorService } from "./services/error"
import { featureFlagsService } from "./services/feature-flags"
import { initializeDistinctId } from "./services/logging/distinctId"
import { PostHogClientProvider } from "./services/posthog/PostHogClientProvider"
import { telemetryService } from "./services/telemetry"
import { ShowMessageType } from "./shared/proto/host/window"
import { getLatestAnnouncementId } from "./utils/announcements"
/**
@@ -23,18 +26,11 @@ import { getLatestAnnouncementId } from "./utils/announcements"
* @returns The webview provider
*/
export async function initialize(context: vscode.ExtensionContext): Promise<WebviewProvider> {
// Set the distinct ID for logging and telemetry
await initializeDistinctId(context)
// Initialize PostHog client provider
let distinctId = context.globalState.get<string>("cline.distinctId")
if (!distinctId) {
try {
const response = await HostProvider.env.getMachineId(EmptyRequest.create({}))
distinctId = response.value
} catch (e) {
Logger.warn(`Failed to get machine ID: ${e instanceof Error ? e.message : String(e)}`)
// PostHogProvider will fall back to uuid
}
}
PostHogClientProvider.getInstance(distinctId)
PostHogClientProvider.getInstance()
// Migrate custom instructions to global Cline rules (one-time cleanup)
await migrateCustomInstructionsToGlobalRules(context)
@@ -45,6 +41,9 @@ export async function initialize(context: vscode.ExtensionContext): Promise<Webv
// Migrate workspace storage values back to global storage (reverting previous migration)
await migrateWorkspaceToGlobalStorage(context)
// Ensure taskHistory.json exists and migrate legacy state (runs once)
await migrateTaskHistoryToFile(context)
// Clean up orphaned file context warnings (startup cleanup)
await FileContextTracker.cleanupOrphanedWarnings(context)
@@ -75,7 +74,7 @@ async function showVersionUpdateAnnouncement(context: vscode.ExtensionContext) {
const message = previousVersion
? `Cline has been updated to v${currentVersion}`
: `Welcome to Cline v${currentVersion}`
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
await HostProvider.workspace.openClineSidebarPanel({})
await new Promise((resolve) => setTimeout(resolve, 200))
HostProvider.window.showMessage({
type: ShowMessageType.INFORMATION,
@@ -96,7 +95,9 @@ async function showVersionUpdateAnnouncement(context: vscode.ExtensionContext) {
*/
export async function tearDown(): Promise<void> {
PostHogClientProvider.getInstance().dispose()
telemetryService.dispose()
errorService.dispose()
featureFlagsService.dispose()
// Dispose all webview instances
await WebviewProvider.disposeAllInstances()
}
+5
View File
@@ -210,6 +210,7 @@ function createHandlerForProvider(
})
case "qwen-code":
return new QwenCodeHandler({
onRetryAttempt: options.onRetryAttempt,
qwenCodeOauthPath: options.qwenCodeOauthPath,
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
})
@@ -312,6 +313,7 @@ function createHandlerForProvider(
})
case "baseten":
return new BasetenHandler({
onRetryAttempt: options.onRetryAttempt,
basetenApiKey: options.basetenApiKey,
basetenModelId: mode === "plan" ? options.planModeBasetenModelId : options.actModeBasetenModelId,
basetenModelInfo: mode === "plan" ? options.planModeBasetenModelInfo : options.actModeBasetenModelInfo,
@@ -341,6 +343,7 @@ function createHandlerForProvider(
})
case "huawei-cloud-maas":
return new HuaweiCloudMaaSHandler({
onRetryAttempt: options.onRetryAttempt,
huaweiCloudMaasApiKey: options.huaweiCloudMaasApiKey,
huaweiCloudMaasModelId:
mode === "plan" ? options.planModeHuaweiCloudMaasModelId : options.actModeHuaweiCloudMaasModelId,
@@ -358,6 +361,7 @@ function createHandlerForProvider(
})
case "vercel-ai-gateway":
return new VercelAIGatewayHandler({
onRetryAttempt: options.onRetryAttempt,
vercelAiGatewayApiKey: options.vercelAiGatewayApiKey,
vercelAiGatewayModelId:
mode === "plan" ? options.planModeVercelAiGatewayModelId : options.actModeVercelAiGatewayModelId,
@@ -366,6 +370,7 @@ function createHandlerForProvider(
})
case "zai":
return new ZAiHandler({
onRetryAttempt: options.onRetryAttempt,
zaiApiLine: options.zaiApiLine,
zaiApiKey: options.zaiApiKey,
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
@@ -0,0 +1,243 @@
import Anthropic from "@anthropic-ai/sdk"
import { LiteLlmHandler, type LiteLlmModelInfoResponse } from "@core/api/providers/litellm"
import { convertToOpenAiMessages } from "@core/api/transform/openai-format"
import { expect } from "chai"
import sinon from "sinon"
const fakeClient = {
chat: {
completions: {
create: sinon.stub(),
},
},
baseURL: "fake",
}
describe("LiteLlmHandler", () => {
const originalFetch = global.fetch
const mockFetch = sinon.stub()
const mockModelFetch = (modelInfo: LiteLlmModelInfoResponse["data"][number]) => {
mockFetch.resolves({
ok: true,
json: () =>
Promise.resolve({
data: [modelInfo],
}),
})
}
let handler: LiteLlmHandler
const mockHandlerChat = () => {
sinon.stub(handler, "ensureClient" as any).returns(fakeClient)
}
const initializeHandler = (model: string) => {
handler = new LiteLlmHandler({
liteLlmApiKey: "test-api-key",
liteLlmBaseUrl: "http://localhost:4000",
liteLlmUsePromptCache: true,
liteLlmModelId: model,
})
mockHandlerChat()
}
beforeEach(() => {
global.fetch = mockFetch
// Configure the stub to return a stream that closes immediately with usage data
fakeClient.chat.completions.create.resolves(
createAsyncIterable([
{
choices: [{ delta: { content: "test response" } }],
},
{
choices: [{}],
usage: {
prompt_tokens: 100,
completion_tokens: 50,
cache_creation_input_tokens: 20,
cache_read_input_tokens: 10,
},
},
]),
)
})
afterEach(() => {
sinon.reset()
global.fetch = originalFetch
})
const createAsyncIterable = (data: any[] = []) => {
return {
[Symbol.asyncIterator]: async function* () {
yield* data
},
}
}
describe("prompt cache", () => {
const setModelData = (model: string, supportsPromptCaching: boolean) => {
mockModelFetch({
model_name: model,
litellm_params: {
model,
},
model_info: {
supports_prompt_caching: supportsPromptCaching,
input_cost_per_token: 0.01,
output_cost_per_token: 0.02,
},
})
}
describe("when the model doesn't support prompt caching", () => {
const model = "openai/gpt-5"
beforeEach(() => {
initializeHandler(model)
setModelData(model, false)
})
it("sends the system prompt and messages with the openai format", async () => {
const systemPrompt = "Test System Prompt"
const messages: Anthropic.Messages.MessageParam[] = [
{
role: "user",
content: "first message",
},
{
role: "assistant",
content: "first response",
},
{
role: "user",
content: [
{
type: "text",
text: "test",
},
{
type: "text",
text: "second message",
},
],
},
]
for await (const _ of handler.createMessage(systemPrompt, messages)) {
}
sinon.assert.calledOnce(fakeClient.chat.completions.create)
const callArgs = fakeClient.chat.completions.create.getCall(0).args[0]
const systemPromptMessage = callArgs.messages.shift()
expect(systemPromptMessage).to.deep.equal({
role: "system",
content: systemPrompt,
})
expect(callArgs.messages).to.deep.equal(convertToOpenAiMessages(messages))
})
})
describe("when the model supports prompt caching", () => {
const model = "anthropic/claude-sonnet-4-20250514"
beforeEach(() => {
initializeHandler(model)
setModelData(model, true)
})
it("inserts the cache control in the system prompt and the last two user messages", async () => {
const systemPrompt = "Test System Prompt"
const messages: Anthropic.Messages.MessageParam[] = [
{
role: "user",
content: "first message",
},
{
role: "assistant",
content: "first response",
},
{
role: "user",
content: [
{
type: "text",
text: "test",
},
{
type: "text",
text: "second message",
},
],
},
]
for await (const _ of handler.createMessage(systemPrompt, messages)) {
}
sinon.assert.calledOnce(fakeClient.chat.completions.create)
const callArgs = fakeClient.chat.completions.create.getCall(0).args[0]
expect(callArgs.messages[0]).to.deep.equal({
role: "system",
content: [
{
text: systemPrompt,
type: "text",
cache_control: {
type: "ephemeral",
},
},
],
})
const sentMessages = callArgs.messages
expect(sentMessages.length).to.equal(4)
const firstUserMessage = sentMessages[1]
expect(firstUserMessage).to.deep.equal({
role: "user",
content: [
{
type: "text",
text: "first message",
cache_control: {
type: "ephemeral",
},
},
],
})
const lastUserMessage = sentMessages[3]
expect(lastUserMessage.content[0]).to.deep.equal({
type: "text",
text: "test",
})
const lastContentBlock = lastUserMessage.content[lastUserMessage.content.length - 1]
expect(lastContentBlock).to.deep.equal({
type: "text",
text: "second message",
cache_control: {
type: "ephemeral",
},
})
expect(callArgs.model).to.be.a("string")
expect(callArgs.stream).to.equal(true)
expect(callArgs.stream_options).to.deep.equal({ include_usage: true })
})
})
})
})
+2 -2
View File
@@ -2,12 +2,12 @@ import { Anthropic } from "@anthropic-ai/sdk"
import { BasetenModelId, basetenDefaultModelId, basetenModels, ModelInfo } from "@shared/api"
import { calculateApiCostOpenAI } from "@utils/cost"
import OpenAI from "openai"
import { ApiHandler } from "../"
import { ApiHandler, CommonApiHandlerOptions } from "../"
import { withRetry } from "../retry"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
interface BasetenHandlerOptions {
interface BasetenHandlerOptions extends CommonApiHandlerOptions {
basetenApiKey?: string
basetenModelId?: string
basetenModelInfo?: ModelInfo
+68 -19
View File
@@ -1,16 +1,18 @@
import type { Anthropic } from "@anthropic-ai/sdk"
// Restore GenerateContentConfig import and add GenerateContentResponseUsageMetadata
import { type GenerateContentConfig, type GenerateContentResponseUsageMetadata, GoogleGenAI, Part } from "@google/genai"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { ApiError, type GenerateContentConfig, type GenerateContentResponseUsageMetadata, GoogleGenAI, Part } from "@google/genai"
import { GeminiModelId, geminiDefaultModelId, geminiModels, ModelInfo } from "@shared/api"
import { telemetryService } from "@/services/telemetry"
import { ApiHandler, CommonApiHandlerOptions } from "../"
import { withRetry } from "../retry"
import { RetriableError, withRetry } from "../retry"
import { convertAnthropicMessageToGemini } from "../transform/gemini-format"
import { ApiStream } from "../transform/stream"
// Define a default TTL for the cache (e.g., 15 minutes in seconds)
const _DEFAULT_CACHE_TTL_SECONDS = 900
const rateLimitPatterns = [/got status: 429/i, /429 Too Many Requests/i, /rate limit exceeded/i, /too many requests/i]
interface GeminiHandlerOptions extends CommonApiHandlerOptions {
isVertex?: boolean
vertexProjectId?: string
@@ -222,24 +224,40 @@ export class GeminiHandler implements ApiHandler {
if (error instanceof Error) {
apiError = error.message
// Gemini doesn't include status codes in their errors
// https://github.com/googleapis/js-genai/blob/61f7f27b866c74333ca6331883882489bcb708b9/src/_api_client.ts#L569
const rateLimitPatterns = [
/got status: 429/i,
/429 Too Many Requests/i,
/rate limit exceeded/i,
/too many requests/i,
]
if (error instanceof ApiError) {
if (error.status === 429) {
// The API includes more details in the message
// https://github.com/googleapis/js-genai/blob/v1.11.0/src/_api_client.ts#L758
const response = this.attemptParse(error.message)
const isRateLimit =
error.name === "ClientError" && rateLimitPatterns.some((pattern) => pattern.test(error.message))
if (response && response.error) {
const responseBody = this.attemptParse(response.error.message)
if (isRateLimit) {
const rateLimitError = Object.assign(new Error(error.message), {
...error,
status: 429,
})
throw rateLimitError
if (responseBody.error) {
const detail = responseBody.error.details?.find(
(d: any) => d["@type"] === "type.googleapis.com/google.rpc.RetryInfo",
)
const detailedError = new RetriableError(
apiError,
this.parseRetryDelay(detail?.retryDelay) || undefined,
{
cause: error,
},
)
throw detailedError
}
}
throw new RetriableError(apiError, undefined, { cause: error })
}
// Fallback in case Gemini throws a rate limit error without a 429 status code
// https://github.com/cline/cline/pull/5205#discussion_r2311761559
const isRateLimit = rateLimitPatterns.some((pattern) => pattern.test(error.message))
if (isRateLimit) {
throw new RetriableError(apiError, undefined, { cause: error })
}
}
} else {
apiError = String(error)
@@ -420,4 +438,35 @@ export class GeminiHandler implements ApiHandler {
return Math.ceil(totalChars / 4)
}
private parseRetryDelay(retryAfter?: string): number {
if (!retryAfter) {
return 0
}
const unit = retryAfter.at(-1)
const value = parseInt(retryAfter, 10)
if (Number.isNaN(value)) {
return 0
}
if (unit === "s") {
return value
} else if (unit === "m") {
return value * 60 // Convert minutes to seconds
} else if (unit === "h") {
return value * 60 * 60 // Convert hours to seconds
}
return value
}
private attemptParse(str: string) {
try {
return JSON.parse(str)
} catch (_) {
return null
}
}
}
+2 -2
View File
@@ -1,12 +1,12 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { HuaweiCloudMaasModelId, huaweiCloudMaasDefaultModelId, huaweiCloudMaasModels, ModelInfo } from "@shared/api"
import OpenAI from "openai"
import { ApiHandler } from ".."
import { ApiHandler, CommonApiHandlerOptions } from ".."
import { withRetry } from "../retry"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
interface HuaweiCloudMaaSHandlerOptions {
interface HuaweiCloudMaaSHandlerOptions extends CommonApiHandlerOptions {
huaweiCloudMaasApiKey?: string
huaweiCloudMaasModelId?: string
huaweiCloudMaasModelInfo?: ModelInfo
+80 -35
View File
@@ -16,7 +16,7 @@ interface LiteLlmHandlerOptions extends CommonApiHandlerOptions {
ulid?: string
}
interface LiteLlmModelInfoResponse {
export interface LiteLlmModelInfoResponse {
data: Array<{
model_name: string
litellm_params: {
@@ -28,6 +28,7 @@ interface LiteLlmModelInfoResponse {
output_cost_per_token: number
cache_creation_input_token_cost?: number
cache_read_input_token_cost?: number
supports_prompt_caching?: boolean
[key: string]: any
}
}>
@@ -61,7 +62,17 @@ export class LiteLlmHandler implements ApiHandler {
return this.client
}
private async fetchModelInfo(): Promise<LiteLlmModelInfoResponse | undefined> {
private async modelInfo(publicModelName: string): Promise<LiteLlmModelInfoResponse["data"][number] | undefined> {
const modelInfo = await this.fetchModelsInfo()
if (!modelInfo?.data) {
return undefined
}
return modelInfo.data.find((model) => model.model_name === publicModelName)
}
private async fetchModelsInfo(): Promise<LiteLlmModelInfoResponse | undefined> {
// Check if cache is still valid
const now = Date.now()
if (this.modelInfoCache && now - this.modelInfoCacheTimestamp < this.modelInfoCacheTTL) {
@@ -121,19 +132,14 @@ export class LiteLlmHandler implements ApiHandler {
cacheReadCostPerToken?: number
}> {
try {
const modelInfo = await this.fetchModelInfo()
const matchingModel = await this.modelInfo(publicModelName)
if (modelInfo?.data) {
// Find the model by public name
const matchingModel = modelInfo.data.find((model) => model.model_name === publicModelName)
if (matchingModel?.model_info) {
return {
inputCostPerToken: matchingModel.model_info.input_cost_per_token || 0,
outputCostPerToken: matchingModel.model_info.output_cost_per_token || 0,
cacheCreationCostPerToken: matchingModel.model_info.cache_creation_input_token_cost,
cacheReadCostPerToken: matchingModel.model_info.cache_read_input_token_cost,
}
if (matchingModel) {
return {
inputCostPerToken: matchingModel.model_info.input_cost_per_token || 0,
outputCostPerToken: matchingModel.model_info.output_cost_per_token || 0,
cacheCreationCostPerToken: matchingModel.model_info.cache_creation_input_token_cost,
cacheReadCostPerToken: matchingModel.model_info.cache_read_input_token_cost,
}
}
} catch (error) {
@@ -177,7 +183,7 @@ export class LiteLlmHandler implements ApiHandler {
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
const client = this.ensureClient()
const formattedMessages = convertToOpenAiMessages(messages)
const systemMessage: OpenAI.Chat.ChatCompletionSystemMessageParam = {
const systemMessage: OpenAI.Chat.ChatCompletionSystemMessageParam | Anthropic.Messages.TextBlockParam = {
role: "system",
content: systemPrompt,
}
@@ -195,13 +201,22 @@ export class LiteLlmHandler implements ApiHandler {
temperature = undefined // Thinking mode doesn't support temperature
}
// Define cache control object if prompt caching is enabled
const cacheControl = this.options.liteLlmUsePromptCache ? { cache_control: { type: "ephemeral" } } : undefined
const modelInfo = await this.modelInfo(modelId)
const cacheControl =
this.options.liteLlmUsePromptCache && Boolean(modelInfo?.model_info.supports_prompt_caching)
? { cache_control: { type: "ephemeral" } }
: undefined
// Add cache_control to system message if enabled
const enhancedSystemMessage = {
...systemMessage,
...(cacheControl && cacheControl),
if (cacheControl) {
// Add cache_control to system message if enabled
// https://docs.litellm.ai/docs/providers/anthropic#caching---large-context-caching
systemMessage.content = [
{
text: systemPrompt,
type: "text",
...cacheControl,
},
] as Anthropic.Messages.TextBlockParam[]
}
// Find the last two user messages to apply caching
@@ -213,19 +228,49 @@ export class LiteLlmHandler implements ApiHandler {
const secondLastUserMsgIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1
// Apply cache_control to the last two user messages if enabled
const enhancedMessages = formattedMessages.map((message, index) => {
if ((index === lastUserMsgIndex || index === secondLastUserMsgIndex) && cacheControl) {
return {
...message,
...cacheControl,
// https://docs.litellm.ai/docs/providers/anthropic#caching---large-context-caching
const enhancedMessages: OpenAI.Chat.ChatCompletionMessageParam[] = formattedMessages.map(
(message, index): OpenAI.Chat.ChatCompletionMessageParam => {
if ((index === lastUserMsgIndex || index === secondLastUserMsgIndex) && cacheControl) {
// Handle both string and array content types
if (typeof message.content === "string") {
return {
...message,
content: [
{
type: "text",
text: message.content,
...cacheControl,
},
] as any,
}
} else if (Array.isArray(message.content)) {
// Apply cache control to the last content item in the array
return {
...message,
content: message.content.map((item, contentIndex) =>
contentIndex === (message.content?.length || 0) - 1
? {
...item,
...cacheControl,
}
: item,
) as any,
}
}
return {
...message,
...cacheControl,
}
}
}
return message
})
return message
},
)
const stream = await client.chat.completions.create({
model: this.options.liteLlmModelId || liteLlmDefaultModelId,
messages: [enhancedSystemMessage, ...enhancedMessages],
messages: [systemMessage, ...enhancedMessages],
temperature,
stream: true,
stream_options: { include_usage: true },
@@ -244,16 +289,16 @@ export class LiteLlmHandler implements ApiHandler {
}
}
// Handle reasoning events (thinking)
// Thinking is not in the standard types but may be in the response
// Handle reasoning events
// This is not in the standard types but may be in the response
interface ThinkingDelta {
thinking?: string
reasoning_content?: string
}
if ((delta as ThinkingDelta)?.thinking) {
if ((delta as ThinkingDelta)?.reasoning_content) {
yield {
type: "reasoning",
reasoning: (delta as ThinkingDelta).thinking || "",
reasoning: (delta as ThinkingDelta).reasoning_content || "",
}
}
+2 -2
View File
@@ -4,7 +4,7 @@ import { ModelInfo, QwenCodeModelId, qwenCodeDefaultModelId, qwenCodeModels } fr
import OpenAI from "openai"
import * as os from "os"
import * as path from "path"
import { ApiHandler } from "../"
import { ApiHandler, CommonApiHandlerOptions } from "../"
import { withRetry } from "../retry"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
@@ -24,7 +24,7 @@ interface QwenOAuthCredentials {
resource_url?: string
}
interface QwenCodeHandlerOptions {
interface QwenCodeHandlerOptions extends CommonApiHandlerOptions {
qwenCodeOauthPath?: string
apiModelId?: string
}
+2 -2
View File
@@ -1,12 +1,12 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ModelInfo, vercelAiGatewayDefaultModelId, vercelAiGatewayDefaultModelInfo } from "@shared/api"
import OpenAI from "openai"
import { ApiHandler } from "../index"
import { ApiHandler, CommonApiHandlerOptions } from "../index"
import { withRetry } from "../retry"
import { ApiStream } from "../transform/stream"
import { createVercelAIGatewayStream } from "../transform/vercel-ai-gateway-stream"
interface VercelAIGatewayHandlerOptions {
interface VercelAIGatewayHandlerOptions extends CommonApiHandlerOptions {
vercelAiGatewayApiKey?: string
vercelAiGatewayModelId?: string
vercelAiGatewayModelInfo?: ModelInfo
+2 -2
View File
@@ -10,12 +10,12 @@ import {
} from "@shared/api"
import OpenAI from "openai"
import { version as extensionVersion } from "../../../../package.json"
import { ApiHandler } from ".."
import { ApiHandler, CommonApiHandlerOptions } from ".."
import { withRetry } from "../retry"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
interface ZAiHandlerOptions {
interface ZAiHandlerOptions extends CommonApiHandlerOptions {
zaiApiLine?: string
zaiApiKey?: string
apiModelId?: string
+15 -2
View File
@@ -12,6 +12,18 @@ const DEFAULT_OPTIONS: Required<RetryOptions> = {
retryAllErrors: false,
}
export class RetriableError extends Error {
status: number = 429
retryAfter?: number
constructor(message: string, retryAfter?: number, options?: ErrorOptions) {
super(message, options)
this.name = "RetriableError"
this.retryAfter = retryAfter
}
}
export function withRetry(options: RetryOptions = {}) {
const { maxRetries, baseDelay, maxDelay, retryAllErrors } = { ...DEFAULT_OPTIONS, ...options }
@@ -24,7 +36,7 @@ export function withRetry(options: RetryOptions = {}) {
yield* originalMethod.apply(this, args)
return
} catch (error: any) {
const isRateLimit = error?.status === 429
const isRateLimit = error?.status === 429 || error instanceof RetriableError
const isLastAttempt = attempt === maxRetries - 1
if ((!isRateLimit && !retryAllErrors) || isLastAttempt) {
@@ -36,7 +48,8 @@ export function withRetry(options: RetryOptions = {}) {
const retryAfter =
error.headers?.["retry-after"] ||
error.headers?.["x-ratelimit-reset"] ||
error.headers?.["ratelimit-reset"]
error.headers?.["ratelimit-reset"] ||
error.retryAfter
let delay: number
if (retryAfter) {
@@ -1,7 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { CLAUDE_SONNET_4_1M_SUFFIX, ModelInfo, openRouterClaudeSonnet41mModelId } from "@shared/api"
import OpenAI from "openai"
import { isGPT5ModelFamily } from "../../prompts/system-prompt/utils"
import { convertToOpenAiMessages } from "./openai-format"
import { convertToR1Format } from "./r1-format"
@@ -1,10 +1,9 @@
import { getTaskMetadata, saveTaskMetadata } from "@core/storage/disk"
import { getTaskMetadata, readTaskHistoryFromState, saveTaskMetadata } from "@core/storage/disk"
import type { ClineMessage } from "@shared/ExtensionMessage"
import chokidar, { FSWatcher } from "chokidar"
import * as path from "path"
import * as vscode from "vscode"
import { Controller } from "@/core/controller"
import { HistoryItem } from "@/shared/HistoryItem"
import { getCwd } from "@/utils/path"
import type { FileMetadataEntry } from "./ContextTrackerTypes"
@@ -286,8 +285,7 @@ export class FileContextTracker {
static async cleanupOrphanedWarnings(context: vscode.ExtensionContext): Promise<void> {
const startTime = Date.now()
try {
// eslint-disable-next-line eslint-rules/no-direct-vscode-state-api
const taskHistory = (context.globalState.get("taskHistory") as HistoryItem[]) || []
const taskHistory = await readTaskHistoryFromState(context)
const existingTaskIds = new Set(taskHistory.map((task) => task.id))
const allStateKeys = context.workspaceState.keys()
const pendingWarningKeys = allStateKeys.filter((key) => key.startsWith("pendingFileContextWarning_"))
@@ -312,7 +310,7 @@ export class FileContextTracker {
`FileContextTracker: Processed ${existingTaskIds.size} tasks, found ${pendingWarningKeys.length} pending warnings, ${orphanedPendingContextTasks.length} orphaned, deleted ${orphanedPendingContextTasks.length}, took ${duration}ms`,
)
} catch (error) {
console.error("Error cleaning up orphaned file context warnings:", error)
console.error("[FileContextTracker] Error cleaning up orphaned file context warnings:", error)
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
import { getFileMentionFromPath } from "@/core/mentions"
import { WebviewProvider } from "@/core/webview"
import { singleFileDiagnosticsToProblemsString } from "@/integrations/diagnostics"
import { telemetryService } from "@/services/posthog/PostHogClientProvider"
import { telemetryService } from "@/services/telemetry"
import { CommandContext, Empty } from "@/shared/proto/index.cline"
import { Controller } from "../index"
import { sendAddToInputEventToClient } from "../ui/subscribeToAddToInput"
@@ -1,6 +1,6 @@
import { getFileMentionFromPath } from "@/core/mentions"
import { HostProvider } from "@/hosts/host-provider"
import { telemetryService } from "@/services/posthog/PostHogClientProvider"
import { telemetryService } from "@/services/telemetry"
import { CommandContext, Empty } from "@/shared/proto/index.cline"
import { ShowMessageType } from "@/shared/proto/index.host"
import { Controller } from "../index"
+1 -1
View File
@@ -1,6 +1,6 @@
import { getFileMentionFromPath } from "@/core/mentions"
import { singleFileDiagnosticsToProblemsString } from "@/integrations/diagnostics"
import { telemetryService } from "@/services/posthog/PostHogClientProvider"
import { telemetryService } from "@/services/telemetry"
import { CommandContext, Empty } from "@/shared/proto/index.cline"
import { Controller } from "../index"
@@ -1,6 +1,6 @@
import { getFileMentionFromPath } from "@/core/mentions"
import { HostProvider } from "@/hosts/host-provider"
import { telemetryService } from "@/services/posthog/PostHogClientProvider"
import { telemetryService } from "@/services/telemetry"
import { CommandContext, Empty } from "@/shared/proto/index.cline"
import { ShowMessageType } from "@/shared/proto/index.host"
import { Controller } from "../index"
@@ -1,5 +1,5 @@
import { openFile as openFileIntegration } from "@integrations/misc/open-file"
import { telemetryService } from "../../../services/posthog/PostHogClientProvider"
import { telemetryService } from "../../../services/telemetry"
import { Empty, StringRequest } from "../../../shared/proto/cline/common"
import { ensureFocusChainFile, extractFocusChainListFromText } from "../../task/focus-chain/file-utils"
import { Controller } from ".."
+1 -1
View File
@@ -1,7 +1,7 @@
import path from "node:path"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import type { ToggleClineRuleRequest } from "@shared/proto/cline/file"
import { ToggleClineRules } from "@shared/proto/cline/file"
import { telemetryService } from "@/services/telemetry"
import type { Controller } from "../index"
/**
@@ -1,4 +1,3 @@
import { ClineRulesToggles as AppClineRulesToggles } from "@shared/cline-rules"
import type { ToggleWindsurfRuleRequest } from "@shared/proto/cline/file"
import { ClineRulesToggles } from "@shared/proto/cline/file"
import type { Controller } from "../index"
+10 -6
View File
@@ -21,7 +21,8 @@ import * as vscode from "vscode"
import { clineEnvConfig } from "@/config"
import { HostProvider } from "@/hosts/host-provider"
import { AuthService } from "@/services/auth/AuthService"
import { PostHogClientProvider, telemetryService } from "@/services/posthog/PostHogClientProvider"
import { getDistinctId } from "@/services/logging/distinctId"
import { telemetryService } from "@/services/telemetry"
import { ShowMessageType } from "@/shared/proto/host/window"
import { getLatestAnnouncementId } from "@/utils/announcements"
import { getCwd, getDesktopDir } from "@/utils/path"
@@ -65,12 +66,15 @@ export class Controller {
this.authService.restoreRefreshTokenAndRetrieveAuthInfo()
})
.catch((error) => {
console.error("CRITICAL: Failed to initialize StateManager - extension may not function properly:", error)
console.error(
"[Controller] CRITICAL: Failed to initialize StateManager - extension may not function properly:",
error,
)
})
// Set up persistence error recovery
this.stateManager.onPersistenceError = async ({ error }: PersistenceErrorEvent) => {
console.error("Cache persistence failed, recovering:", error)
console.error("[Controller] Cache persistence failed, recovering:", error)
try {
await this.stateManager.reInitialize()
await this.postStateToWebview()
@@ -79,7 +83,7 @@ export class Controller {
message: "Saving settings to storage failed.",
})
} catch (recoveryError) {
console.error("Cache recovery failed:", recoveryError)
console.error("[Controller] Cache recovery failed:", recoveryError)
HostProvider.window.showMessage({
type: ShowMessageType.ERROR,
message: "Failed to save settings. Please restart the extension.",
@@ -212,7 +216,7 @@ export class Controller {
openaiReasoningEffort,
mode,
strictPlanModeEnabled ?? true,
useAutoCondense ?? true,
useAutoCondense ?? false,
shellIntegrationTimeout,
terminalReuseEnabled ?? true,
terminalOutputLineLimit ?? 500,
@@ -636,7 +640,7 @@ export class Controller {
const latestAnnouncementId = getLatestAnnouncementId(this.context)
const shouldShowAnnouncement = lastShownAnnouncementId !== latestAnnouncementId
const platform = process.platform as Platform
const distinctId = PostHogClientProvider.getInstance().distinctId
const distinctId = getDistinctId()
const version = this.context.extension?.packageJSON?.version ?? ""
const uriScheme = vscode.env.uriScheme
@@ -5,7 +5,7 @@ import { fileExistsAtPath } from "@utils/fs"
import axios from "axios"
import fs from "fs/promises"
import path from "path"
import { telemetryService } from "@/services/posthog/PostHogClientProvider"
import { telemetryService } from "@/services/telemetry"
import { groqModels } from "../../../shared/api"
import { Controller } from ".."
@@ -110,6 +110,12 @@ export async function refreshOpenRouterModels(
switch (rawModel.id) {
case "anthropic/claude-sonnet-4":
// NOTE: we artificially restrict the context window to 200k to keep costs low for users, and have a :1m model variant created below for users that want to use the full 1m.
modelInfo.contextWindow = 200_000
modelInfo.supportsPromptCache = true
modelInfo.cacheWritesPrice = 3.75
modelInfo.cacheReadsPrice = 0.3
break
case "anthropic/claude-3-7-sonnet":
case "anthropic/claude-3-7-sonnet:beta":
case "anthropic/claude-3.7-sonnet":
@@ -183,6 +189,10 @@ export async function refreshOpenRouterModels(
modelInfo.maxTokens = 8_192 // 128000 breaks context window truncation
modelInfo.contextWindow = 272_000 // openrouter reports 400k but the input limit is actually 400k-128k
break
case "x-ai/grok-code-fast-1":
modelInfo.supportsPromptCache = true
modelInfo.cacheReadsPrice = 0.02
break
default:
if (rawModel.id.startsWith("openai/")) {
modelInfo.cacheReadsPrice = parsePrice(rawModel.pricing?.input_cache_read)
@@ -1,5 +1,5 @@
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { Empty, StringRequest } from "@shared/proto/cline/common"
import { telemetryService } from "@/services/telemetry"
import { Controller } from ".."
/**
+1 -1
View File
@@ -10,7 +10,7 @@ import { convertProtoApiConfigurationToApiConfiguration } from "@shared/proto-co
import { OpenaiReasoningEffort } from "@shared/storage/types"
import { TelemetrySetting } from "@shared/TelemetrySetting"
import { McpDisplayMode } from "@/shared/McpDisplayMode"
import { telemetryService } from "../../../services/posthog/PostHogClientProvider"
import { telemetryService } from "../../../services/telemetry"
import { Controller } from ".."
/**
+1 -1
View File
@@ -1,5 +1,5 @@
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { Empty, StringRequest } from "@shared/proto/cline/common"
import { telemetryService } from "@/services/telemetry"
import { Controller } from ".."
/**
+2 -1
View File
@@ -1,7 +1,8 @@
import { McpMarketplaceCatalog } from "@shared/mcp"
import { Empty, EmptyRequest } from "@shared/proto/cline/common"
import { OpenRouterCompatibleModelInfo } from "@shared/proto/cline/models"
import { featureFlagsService, telemetryService } from "@/services/posthog/PostHogClientProvider"
import { featureFlagsService } from "@/services/feature-flags"
import { telemetryService } from "@/services/telemetry"
import type { Controller } from "../index"
import { sendMcpMarketplaceCatalogEvent } from "../mcp/subscribeToMcpMarketplaceCatalog"
import { refreshBasetenModels } from "../models/refreshBasetenModels"
+1 -1
View File
@@ -1,7 +1,7 @@
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import type { EmptyRequest } from "@shared/proto/cline/common"
import { Empty } from "@shared/proto/cline/common"
import * as vscode from "vscode"
import { telemetryService } from "@/services/telemetry"
import type { Controller } from "../index"
/**
+9 -3
View File
@@ -7,6 +7,8 @@ You have only two options: If you are immediately prepared to call the attempt_c
You MUST ONLY respond to this message by using either the attempt_completion tool or the summarize_task tool call.
When responding with the summarize_task tool call, follow these instructions:
Before providing your final summary, wrap your analysis in <thinking> tags to organize your thoughts and ensure you've covered all necessary points. In your analysis process:
1. Chronologically analyze each message and section of the conversation. For each section thoroughly identify:
- The user's explicit requests and intents
@@ -21,10 +23,14 @@ Your summary should include the following sections:
3. Files and Code Sections: Enumerate specific files and code sections examined, modified, or created. Pay special attention to the most recent messages and include full code snippets where applicable and include a summary of why this file read or edit is important.
4. Problem Solving: Document problems solved and any ongoing troubleshooting efforts.
5. Pending Tasks: Outline any pending tasks that you have explicitly been asked to work on.
6. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
7. Optional Next Step: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's explicit requests, and the task you were working on immediately before this summary request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests without confirming with the user first.
6. Task Evolution: If the user provided additional requests or modified the original task during the conversation, document this progression:
- Task Modifications: [Chronological list of how the user redirected or modified the work since the original task]
- Current Active Task: [What the user most recently asked to work on]
- Context for Changes: [Why the task evolved - user feedback, new requirements, etc. (Include direct quotes from user messages that caused task changes to prevent drift after context compacting)]
7. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
8. Next Step: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's explicit requests, and the task you were working on immediately before this summary request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests without confirming with the user first.
If there is a next step, include direct quotes from the most recent conversation showing exactly what task you were working on and where you left off. This should be verbatim to ensure there's no drift in task interpretation.
8. You should pay special attention to the most recent user message, as it indicates the user's most recent intent, if applicable.
9. You should pay special attention to the most recent user message, as it indicates the user's most recent intent.
${
focusChainSettings?.enabled
+1 -1
View File
@@ -9,7 +9,7 @@ export const formatResponse = {
`[[NOTE] This file read has been removed to save space in the context window. Refer to the latest file read for the most up to date version of this file.]`,
contextTruncationNotice: () =>
`[NOTE] Some previous conversation history with the user has been removed to maintain optimal context window length. The initial user task has been retained for continuity, while intermediate conversation history has been removed. Please keep this in mind as you continue assisting the user.`,
`[NOTE] Some previous conversation history with the user has been removed to maintain optimal context window length. The initial user task has been retained for continuity, while intermediate conversation history has been removed. Keep this in mind as you continue assisting the user. Pay special attention to the user's latest messages.`,
processFirstUserMessageForTruncation: (originalContent: string) => {
const MAX_CHARS = 400_000
@@ -30,8 +30,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -71,7 +71,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -105,11 +104,13 @@ Parameters:
- path: (required) The path of the directory to search in (relative to the current working directory /test/project). This directory will be recursively searched.
- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<search_files>
<path>Directory path here</path>
<regex>Your regex pattern here</regex>
<file_pattern>file pattern here (optional)</file_pattern>
<task_progress>Checklist here (optional)</task_progress>
</search_files>
## list_files
@@ -117,19 +118,23 @@ Description: Request to list files and directories within the specified director
Parameters:
- path: (required) The path of the directory to list contents for (relative to the current working directory /test/project)
- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_files>
<path>Directory path here</path>
<recursive>true or false (optional)</recursive>
<task_progress>Checklist here (optional)</task_progress>
</list_files>
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
- path: (required) The path of the directory (relative to the current working directory /test/project) to list top level source code definitions for.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_code_definition_names>
<path>Directory path here</path>
<task_progress>Checklist here (optional)</task_progress>
</list_code_definition_names>
## browser_action
@@ -139,10 +144,25 @@ Description: Request to interact with a Puppeteer-controlled browser. Every acti
- The browser window has a resolution of **1280x720** pixels. When performing any click actions, ensure the coordinates are within this resolution range.
- Before clicking on any elements such as icons, links, or buttons, you must consult the provided screenshot of the page to determine the coordinates of the element. The click should be targeted at the **center of the element**, not on its edges.
Parameters:
- action: (required) The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution. * Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>
- action: (required) The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the `url` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the `coordinate` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the `text` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action.
* Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution.
* Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action.
* Example: <text>Hello, world!</text>
Usage:
<browser_action>
<action>Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)</action>
@@ -162,9 +182,11 @@ Description: Fetches content from a specified URL and processes into markdown
- This tool is read-only and does not modify any files
Parameters:
- url: (required) The URL to fetch content from
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<web_fetch>
<url>https://example.com/docs</url>
<task_progress>Checklist here (optional)</task_progress>
</web_fetch>
## use_mcp_tool
@@ -173,28 +195,30 @@ Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
<task_progress>Checklist here (optional)</task_progress>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
<task_progress>Checklist here (optional)</task_progress>
</access_mcp_resource>
@@ -202,11 +226,13 @@ Usage:
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<ask_followup_question>
<question>Your question here</question>
<options>Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]</options>
<task_progress>Checklist here (optional)</task_progress>
</ask_followup_question>
## attempt_completion
@@ -225,7 +251,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -250,11 +276,15 @@ Usage:
<plan_mode_respond>
<response>Your response here</response>
<needs_more_exploration>true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)</needs_more_exploration>
<task_progress>Checklist here (optional)</task_progress>
<task_progress>Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)</task_progress>
</plan_mode_respond>
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -337,9 +367,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -350,15 +378,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -396,7 +421,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -30,8 +30,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -71,7 +71,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -105,11 +104,13 @@ Parameters:
- path: (required) The path of the directory to search in (relative to the current working directory /test/project). This directory will be recursively searched.
- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<search_files>
<path>Directory path here</path>
<regex>Your regex pattern here</regex>
<file_pattern>file pattern here (optional)</file_pattern>
<task_progress>Checklist here (optional)</task_progress>
</search_files>
## list_files
@@ -117,19 +118,23 @@ Description: Request to list files and directories within the specified director
Parameters:
- path: (required) The path of the directory to list contents for (relative to the current working directory /test/project)
- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_files>
<path>Directory path here</path>
<recursive>true or false (optional)</recursive>
<task_progress>Checklist here (optional)</task_progress>
</list_files>
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
- path: (required) The path of the directory (relative to the current working directory /test/project) to list top level source code definitions for.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_code_definition_names>
<path>Directory path here</path>
<task_progress>Checklist here (optional)</task_progress>
</list_code_definition_names>
## web_fetch
@@ -143,9 +148,11 @@ Description: Fetches content from a specified URL and processes into markdown
- This tool is read-only and does not modify any files
Parameters:
- url: (required) The URL to fetch content from
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<web_fetch>
<url>https://example.com/docs</url>
<task_progress>Checklist here (optional)</task_progress>
</web_fetch>
## use_mcp_tool
@@ -154,28 +161,30 @@ Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
<task_progress>Checklist here (optional)</task_progress>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
<task_progress>Checklist here (optional)</task_progress>
</access_mcp_resource>
@@ -183,11 +192,13 @@ Usage:
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<ask_followup_question>
<question>Your question here</question>
<options>Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]</options>
<task_progress>Checklist here (optional)</task_progress>
</ask_followup_question>
## attempt_completion
@@ -206,7 +217,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -231,11 +242,15 @@ Usage:
<plan_mode_respond>
<response>Your response here</response>
<needs_more_exploration>true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)</needs_more_exploration>
<task_progress>Checklist here (optional)</task_progress>
<task_progress>Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)</task_progress>
</plan_mode_respond>
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -318,9 +333,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -331,15 +344,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -377,7 +387,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -27,8 +27,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -64,7 +64,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -130,10 +129,25 @@ Description: Request to interact with a Puppeteer-controlled browser. Every acti
- The browser window has a resolution of **1280x720** pixels. When performing any click actions, ensure the coordinates are within this resolution range.
- Before clicking on any elements such as icons, links, or buttons, you must consult the provided screenshot of the page to determine the coordinates of the element. The click should be targeted at the **center of the element**, not on its edges.
Parameters:
- action: (required) The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution. * Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>
- action: (required) The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the `url` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the `coordinate` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the `text` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action.
* Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution.
* Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action.
* Example: <text>Hello, world!</text>
Usage:
<browser_action>
<action>Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)</action>
@@ -168,28 +182,30 @@ Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
</access_mcp_resource>
## ask_followup_question
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
Usage:
<ask_followup_question>
<question>Your question here</question>
@@ -209,7 +225,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -237,6 +253,10 @@ Usage:
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -307,9 +327,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -320,15 +338,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -360,7 +375,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -30,8 +30,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -71,7 +71,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -105,11 +104,13 @@ Parameters:
- path: (required) The path of the directory to search in (relative to the current working directory /test/project). This directory will be recursively searched.
- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<search_files>
<path>Directory path here</path>
<regex>Your regex pattern here</regex>
<file_pattern>file pattern here (optional)</file_pattern>
<task_progress>Checklist here (optional)</task_progress>
</search_files>
## list_files
@@ -117,19 +118,23 @@ Description: Request to list files and directories within the specified director
Parameters:
- path: (required) The path of the directory to list contents for (relative to the current working directory /test/project)
- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_files>
<path>Directory path here</path>
<recursive>true or false (optional)</recursive>
<task_progress>Checklist here (optional)</task_progress>
</list_files>
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
- path: (required) The path of the directory (relative to the current working directory /test/project) to list top level source code definitions for.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_code_definition_names>
<path>Directory path here</path>
<task_progress>Checklist here (optional)</task_progress>
</list_code_definition_names>
## browser_action
@@ -139,10 +144,25 @@ Description: Request to interact with a Puppeteer-controlled browser. Every acti
- The browser window has a resolution of **1280x720** pixels. When performing any click actions, ensure the coordinates are within this resolution range.
- Before clicking on any elements such as icons, links, or buttons, you must consult the provided screenshot of the page to determine the coordinates of the element. The click should be targeted at the **center of the element**, not on its edges.
Parameters:
- action: (required) The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution. * Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>
- action: (required) The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the `url` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the `coordinate` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the `text` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action.
* Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution.
* Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action.
* Example: <text>Hello, world!</text>
Usage:
<browser_action>
<action>Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)</action>
@@ -162,9 +182,11 @@ Description: Fetches content from a specified URL and processes into markdown
- This tool is read-only and does not modify any files
Parameters:
- url: (required) The URL to fetch content from
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<web_fetch>
<url>https://example.com/docs</url>
<task_progress>Checklist here (optional)</task_progress>
</web_fetch>
## use_mcp_tool
@@ -173,28 +195,30 @@ Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
<task_progress>Checklist here (optional)</task_progress>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
<task_progress>Checklist here (optional)</task_progress>
</access_mcp_resource>
@@ -202,11 +226,13 @@ Usage:
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<ask_followup_question>
<question>Your question here</question>
<options>Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]</options>
<task_progress>Checklist here (optional)</task_progress>
</ask_followup_question>
## attempt_completion
@@ -225,7 +251,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -250,11 +276,15 @@ Usage:
<plan_mode_respond>
<response>Your response here</response>
<needs_more_exploration>true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)</needs_more_exploration>
<task_progress>Checklist here (optional)</task_progress>
<task_progress>Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)</task_progress>
</plan_mode_respond>
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -337,9 +367,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -350,15 +378,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -396,7 +421,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -57,9 +57,7 @@ Key: If output doesnt stream, assume success unless critical; else ask user t
<diff>
------- SEARCH
console.log('Hi');
=======
console.log('Hello');
+++++++ REPLACE
</diff>
@@ -57,9 +57,7 @@ Key: If output doesnt stream, assume success unless critical; else ask user t
<diff>
------- SEARCH
console.log('Hi');
=======
console.log('Hello');
+++++++ REPLACE
</diff>
@@ -57,9 +57,7 @@ Key: If output doesnt stream, assume success unless critical; else ask user t
<diff>
------- SEARCH
console.log('Hi');
=======
console.log('Hello');
+++++++ REPLACE
</diff>
@@ -57,9 +57,7 @@ Key: If output doesnt stream, assume success unless critical; else ask user t
<diff>
------- SEARCH
console.log('Hi');
=======
console.log('Hello');
+++++++ REPLACE
</diff>
@@ -30,8 +30,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -71,7 +71,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -105,11 +104,13 @@ Parameters:
- path: (required) The path of the directory to search in (relative to the current working directory /test/project). This directory will be recursively searched.
- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<search_files>
<path>Directory path here</path>
<regex>Your regex pattern here</regex>
<file_pattern>file pattern here (optional)</file_pattern>
<task_progress>Checklist here (optional)</task_progress>
</search_files>
## list_files
@@ -117,19 +118,23 @@ Description: Request to list files and directories within the specified director
Parameters:
- path: (required) The path of the directory to list contents for (relative to the current working directory /test/project)
- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_files>
<path>Directory path here</path>
<recursive>true or false (optional)</recursive>
<task_progress>Checklist here (optional)</task_progress>
</list_files>
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
- path: (required) The path of the directory (relative to the current working directory /test/project) to list top level source code definitions for.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_code_definition_names>
<path>Directory path here</path>
<task_progress>Checklist here (optional)</task_progress>
</list_code_definition_names>
## browser_action
@@ -139,10 +144,25 @@ Description: Request to interact with a Puppeteer-controlled browser. Every acti
- The browser window has a resolution of **1280x720** pixels. When performing any click actions, ensure the coordinates are within this resolution range.
- Before clicking on any elements such as icons, links, or buttons, you must consult the provided screenshot of the page to determine the coordinates of the element. The click should be targeted at the **center of the element**, not on its edges.
Parameters:
- action: (required) The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution. * Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>
- action: (required) The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the `url` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the `coordinate` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the `text` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action.
* Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution.
* Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action.
* Example: <text>Hello, world!</text>
Usage:
<browser_action>
<action>Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)</action>
@@ -157,28 +177,30 @@ Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
<task_progress>Checklist here (optional)</task_progress>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
<task_progress>Checklist here (optional)</task_progress>
</access_mcp_resource>
@@ -186,11 +208,13 @@ Usage:
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<ask_followup_question>
<question>Your question here</question>
<options>Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]</options>
<task_progress>Checklist here (optional)</task_progress>
</ask_followup_question>
## attempt_completion
@@ -209,7 +233,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -234,11 +258,15 @@ Usage:
<plan_mode_respond>
<response>Your response here</response>
<needs_more_exploration>true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)</needs_more_exploration>
<task_progress>Checklist here (optional)</task_progress>
<task_progress>Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)</task_progress>
</plan_mode_respond>
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -321,9 +349,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -334,15 +360,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -380,7 +403,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -30,8 +30,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -71,7 +71,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -105,11 +104,13 @@ Parameters:
- path: (required) The path of the directory to search in (relative to the current working directory /test/project). This directory will be recursively searched.
- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<search_files>
<path>Directory path here</path>
<regex>Your regex pattern here</regex>
<file_pattern>file pattern here (optional)</file_pattern>
<task_progress>Checklist here (optional)</task_progress>
</search_files>
## list_files
@@ -117,19 +118,23 @@ Description: Request to list files and directories within the specified director
Parameters:
- path: (required) The path of the directory to list contents for (relative to the current working directory /test/project)
- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_files>
<path>Directory path here</path>
<recursive>true or false (optional)</recursive>
<task_progress>Checklist here (optional)</task_progress>
</list_files>
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
- path: (required) The path of the directory (relative to the current working directory /test/project) to list top level source code definitions for.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_code_definition_names>
<path>Directory path here</path>
<task_progress>Checklist here (optional)</task_progress>
</list_code_definition_names>
## use_mcp_tool
@@ -138,28 +143,30 @@ Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
<task_progress>Checklist here (optional)</task_progress>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
<task_progress>Checklist here (optional)</task_progress>
</access_mcp_resource>
@@ -167,11 +174,13 @@ Usage:
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<ask_followup_question>
<question>Your question here</question>
<options>Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]</options>
<task_progress>Checklist here (optional)</task_progress>
</ask_followup_question>
## attempt_completion
@@ -190,7 +199,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -215,11 +224,15 @@ Usage:
<plan_mode_respond>
<response>Your response here</response>
<needs_more_exploration>true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)</needs_more_exploration>
<task_progress>Checklist here (optional)</task_progress>
<task_progress>Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)</task_progress>
</plan_mode_respond>
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -302,9 +315,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -315,15 +326,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -361,7 +369,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -27,8 +27,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -64,7 +64,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -130,10 +129,25 @@ Description: Request to interact with a Puppeteer-controlled browser. Every acti
- The browser window has a resolution of **1280x720** pixels. When performing any click actions, ensure the coordinates are within this resolution range.
- Before clicking on any elements such as icons, links, or buttons, you must consult the provided screenshot of the page to determine the coordinates of the element. The click should be targeted at the **center of the element**, not on its edges.
Parameters:
- action: (required) The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution. * Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>
- action: (required) The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the `url` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the `coordinate` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the `text` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action.
* Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution.
* Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action.
* Example: <text>Hello, world!</text>
Usage:
<browser_action>
<action>Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)</action>
@@ -152,28 +166,30 @@ Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
</access_mcp_resource>
## ask_followup_question
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
Usage:
<ask_followup_question>
<question>Your question here</question>
@@ -193,7 +209,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -221,6 +237,10 @@ Usage:
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -291,9 +311,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -304,15 +322,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -344,7 +359,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -30,8 +30,8 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: /test/project
Parameters:
- command: (required) The CLI command to execute...
- requires_approval: (required) A boolean indicating whether...
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
@@ -71,7 +71,6 @@ Parameters:
------- SEARCH
[exact content to find]
=======
[new content to replace with]
+++++++ REPLACE
```
@@ -105,11 +104,13 @@ Parameters:
- path: (required) The path of the directory to search in (relative to the current working directory /test/project). This directory will be recursively searched.
- regex: (required) The regular expression pattern to search for. Uses Rust regex syntax.
- file_pattern: (optional) Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<search_files>
<path>Directory path here</path>
<regex>Your regex pattern here</regex>
<file_pattern>file pattern here (optional)</file_pattern>
<task_progress>Checklist here (optional)</task_progress>
</search_files>
## list_files
@@ -117,19 +118,23 @@ Description: Request to list files and directories within the specified director
Parameters:
- path: (required) The path of the directory to list contents for (relative to the current working directory /test/project)
- recursive: (optional) Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_files>
<path>Directory path here</path>
<recursive>true or false (optional)</recursive>
<task_progress>Checklist here (optional)</task_progress>
</list_files>
## list_code_definition_names
Description: Request to list definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture.
Parameters:
- path: (required) The path of the directory (relative to the current working directory /test/project) to list top level source code definitions for.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<list_code_definition_names>
<path>Directory path here</path>
<task_progress>Checklist here (optional)</task_progress>
</list_code_definition_names>
## browser_action
@@ -139,10 +144,25 @@ Description: Request to interact with a Puppeteer-controlled browser. Every acti
- The browser window has a resolution of **1280x720** pixels. When performing any click actions, ensure the coordinates are within this resolution range.
- Before clicking on any elements such as icons, links, or buttons, you must consult the provided screenshot of the page to determine the coordinates of the element. The click should be targeted at the **center of the element**, not on its edges.
Parameters:
- action: (required) The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution. * Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>
- action: (required) The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the `url` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the `coordinate` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the `text` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: `<action>close</action>`
- url: (optional) Use this for providing the URL for the `launch` action.
* Example: <url>https://example.com</url>
- coordinate: (optional) The X and Y coordinates for the `click` action. Coordinates should be within the **1280x720** resolution.
* Example: <coordinate>450,300</coordinate>
- text: (optional) Use this for providing the text for the `type` action.
* Example: <text>Hello, world!</text>
Usage:
<browser_action>
<action>Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)</action>
@@ -157,28 +177,30 @@ Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>{
<arguments>
{
"param1": "value1",
"param2": "value2"
}</arguments>
}
</arguments>
<task_progress>Checklist here (optional)</task_progress>
</use_mcp_tool>
## access_mcp_resource
Description: The name of the MCP server providing the resource.
Description: Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.
Parameters:
- server_name: (required) server name here
- uri: (required) resource URI here
- server_name: (required) The name of the MCP server providing the resource
- uri: (required) The URI identifying the specific resource to access
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<access_mcp_resource>
<server_name></server_name>
<uri></uri>
<server_name>server name here</server_name>
<uri>resource URI here</uri>
<task_progress>Checklist here (optional)</task_progress>
</access_mcp_resource>
@@ -186,11 +208,13 @@ Usage:
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.
- options: (optional) An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.
- task_progress: (optional) A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)
Usage:
<ask_followup_question>
<question>Your question here</question>
<options>Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]</options>
<task_progress>Checklist here (optional)</task_progress>
</ask_followup_question>
## attempt_completion
@@ -209,7 +233,7 @@ Usage:
</attempt_completion>
## new_task
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Description: Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.
Parameters:
- context: (required) The context to preload the new task with. If applicable based on the current task, this should include:
@@ -234,11 +258,15 @@ Usage:
<plan_mode_respond>
<response>Your response here</response>
<needs_more_exploration>true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)</needs_more_exploration>
<task_progress>Checklist here (optional)</task_progress>
<task_progress>Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)</task_progress>
</plan_mode_respond>
## load_mcp_documentation
Description: Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with `use_mcp_tool` and `access_mcp_resource`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>
# Tool Use Examples
@@ -321,9 +349,7 @@ Description: Load documentation about creating MCP servers. This tool should be
<diff>
------- SEARCH
import React from 'react';
=======
import React, { useState } from 'react';
+++++++ REPLACE
@@ -334,15 +360,12 @@ function handleSubmit() {
}
=======
+++++++ REPLACE
------- SEARCH
return (
<div>
=======
function handleSubmit() {
saveData();
setLoading(false);
@@ -380,7 +403,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -63,7 +63,9 @@ ${differences}
// Helper to compare two strings and return differences
const compareStrings = (expected: string, actual: string): string | null => {
if (expected === actual) return null
if (expected === actual) {
return null
}
const expectedLines = expected.split("\n")
const actualLines = actual.split("\n")
@@ -143,7 +143,7 @@ return (
<tool_name>create_issue</tool_name>
<arguments>
{
"owner": "octocat",
"owner": "octocat2",
"repo": "hello-world",
"title": "Found a bug",
"body": "I'm having a problem with this.",
@@ -94,8 +94,23 @@ export class PromptBuilder {
.trim() // Remove leading/trailing whitespace
.replace(/====+\s*$/, "") // Remove trailing ==== after trim
.replace(/\n====+\s*\n+\s*====+\n/g, "\n====\n") // Remove empty sections between separators
.replace(/====\n([^\n])/g, "====\n\n$1") // Ensure proper section separation
.replace(/([^\n])\n====/g, "$1\n\n====")
.replace(/====+\n(?!\n)([^\n])/g, (match, nextChar, offset, string) => {
// Add extra newline after ====+ if not already followed by a newline
// Exception: preserve single newlines when ====+ appears to be part of diff-like content
// Look for patterns like "SEARCH\n=======\n" or ";\n=======\n" (diff markers)
const beforeContext = string.substring(Math.max(0, offset - 50), offset)
const afterContext = string.substring(offset, Math.min(string.length, offset + 50))
const isDiffLike = /SEARCH|REPLACE|\+\+\+\+\+\+\+|-------/.test(beforeContext + afterContext)
return isDiffLike ? match : match.replace(/\n/, "\n\n")
})
.replace(/([^\n])\n(?!\n)====+/g, (match, prevChar, offset, string) => {
// Add extra newline before ====+ if not already preceded by a newline
// Exception: preserve single newlines when ====+ appears to be part of diff-like content
const beforeContext = string.substring(Math.max(0, offset - 50), offset)
const afterContext = string.substring(offset, Math.min(string.length, offset + 50))
const isDiffLike = /SEARCH|REPLACE|\+\+\+\+\+\+\+|-------/.test(beforeContext + afterContext)
return isDiffLike ? match : prevChar + "\n\n" + match.substring(1).replace(/\n/, "")
})
}
getBuildMetadata(): {
@@ -3,6 +3,8 @@ import { getModelFamily } from ".."
import { getSystemPromptComponents } from "../components"
import { registerClineToolSets } from "../tools"
import type { ComponentFunction, ComponentRegistry, PromptVariant, SystemPromptContext } from "../types"
import { loadAllVariantConfigs } from "../variants"
import { config as genericConfig } from "../variants/generic/config"
import { PromptBuilder } from "./PromptBuilder"
export class PromptRegistry {
@@ -32,9 +34,37 @@ export class PromptRegistry {
await Promise.all([this.loadVariants(), this.loadComponents()])
// Perform health check to ensure critical variants are available
this.performHealthCheck()
this.loaded = true
}
/**
* Perform health check to ensure registry is in a valid state
*/
private performHealthCheck(): void {
const criticalVariants = [ModelFamily.GENERIC]
const missingVariants = criticalVariants.filter((variant) => !this.variants.has(variant))
if (missingVariants.length > 0) {
console.error(`Registry health check failed: Missing critical variants: ${missingVariants.join(", ")}`)
console.error(`Available variants: ${Array.from(this.variants.keys()).join(", ")}`)
}
if (this.variants.size === 0) {
console.error("Registry health check failed: No variants loaded at all")
}
if (Object.keys(this.components).length === 0) {
console.warn("Registry health check warning: No components loaded")
}
console.log(
`Registry health check: ${this.variants.size} variants, ${Object.keys(this.components).length} components loaded`,
)
}
/**
* Get prompt by model ID with fallback to generic
*/
@@ -43,11 +73,31 @@ export class PromptRegistry {
// Try model family fallback (e.g., "claude-4" -> "claude")
const modelFamily = getModelFamily(context.providerInfo)
const variant = this.variants.get(modelFamily ?? ModelFamily.GENERIC)
let variant = this.variants.get(modelFamily ?? ModelFamily.GENERIC)
// If no variant found for the detected family, explicitly try generic
if (!variant && modelFamily !== ModelFamily.GENERIC) {
variant = this.variants.get(ModelFamily.GENERIC)
}
if (!variant) {
// Enhanced error with debugging information
const availableVariants = Array.from(this.variants.keys())
const errorDetails = {
requestedModel: context.providerInfo.model.id,
detectedFamily: modelFamily,
availableVariants,
variantsCount: this.variants.size,
componentsCount: Object.keys(this.components).length,
isLoaded: this.loaded,
}
console.error("Prompt variant lookup failed:", errorDetails)
throw new Error(
`No prompt variant found for model '${context.providerInfo.model.id}' and no generic fallback available`,
`No prompt variant found for model '${context.providerInfo.model.id}' (family: ${modelFamily}) and no generic fallback available. ` +
`Available variants: [${availableVariants.join(", ")}]. ` +
`Registry state: loaded=${this.loaded}, variants=${this.variants.size}, components=${Object.keys(this.components).length}`,
)
}
@@ -184,30 +234,44 @@ export class PromptRegistry {
/**
* Load all variants from the variants directory
*/
private async loadVariants(): Promise<void> {
private loadVariants(): void {
try {
const { VARIANT_CONFIGS } = await import("../variants")
this.variants = new Map<string, PromptVariant>()
// Load each variant configuration
const loadPromises = Object.entries(VARIANT_CONFIGS).map(async ([variantId, configLoader]) => {
try {
const config = await configLoader()
await this.loadVariantFromConfig(variantId, config)
} catch (error) {
console.warn(`Warning: Could not load variant '${variantId}':`, error)
}
})
for (const [id, config] of Object.entries(loadAllVariantConfigs())) {
this.variants.set(id, { ...config, id })
}
await Promise.all(loadPromises)
// Ensure generic variant is always available as a safety fallback
this.ensureGenericFallback()
} catch (error) {
console.warn("Warning: Could not load variants:", error)
// Even if variant loading fails completely, create a minimal generic fallback
this.createMinimalGenericFallback()
}
}
/**
* Ensure generic variant is available, create minimal one if missing
*/
private ensureGenericFallback(): void {
if (!this.variants.has(ModelFamily.GENERIC)) {
console.warn("Generic variant not found, creating minimal fallback")
this.createMinimalGenericFallback()
}
}
/**
* Create a minimal generic variant as absolute fallback
*/
private createMinimalGenericFallback(): void {
this.loadVariantFromConfig(ModelFamily.GENERIC, genericConfig)
}
/**
* Load a single variant from its TypeScript config
*/
private async loadVariantFromConfig(variantId: string, config: Omit<PromptVariant, "id">): Promise<void> {
private loadVariantFromConfig(variantId: string, config: Omit<PromptVariant, "id">): void {
try {
const variant: PromptVariant = {
...config,
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
/**
* ## access_mcp_resource
@@ -23,27 +24,23 @@ const generic: ClineToolSpec = {
variant: ModelFamily.GENERIC,
id: ClineDefaultTool.MCP_ACCESS,
name: "access_mcp_resource",
description: "The name of the MCP server providing the resource.",
description:
"Request to access a resource provided by a connected MCP server. Resources represent data sources that can be used as context, such as files, API responses, or system information.",
contextRequirements: (context) => context.mcpHub !== undefined && context.mcpHub !== null,
parameters: [
{
name: "server_name",
required: true,
instruction: "server name here",
instruction: "The name of the MCP server providing the resource",
usage: "server name here",
},
{
name: "uri",
required: true,
instruction: "resource URI here",
},
{
name: "task_progress",
required: false,
instruction:
"A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)",
usage: "Checklist here (optional)",
dependencies: [ClineDefaultTool.TODO],
instruction: "The URI identifying the specific resource to access",
usage: "resource URI here",
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const generic: ClineToolSpec = {
variant: ModelFamily.GENERIC,
@@ -20,9 +21,10 @@ const generic: ClineToolSpec = {
name: "options",
required: false,
instruction:
"An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer.",
"An array of 2-5 options for the user to choose from. Each option should be a string describing a possible answer. You may not always need to provide options, but it may be helpful in many cases where it can save the user from having to type out a response manually. IMPORTANT: NEVER include an option to toggle to Act mode, as this would be something you need to direct the user to do manually themselves if needed.",
usage: 'Array of options here (optional), e.g. ["Option 1", "Option 2", "Option 3"]',
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -24,6 +24,7 @@ IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user th
"A CLI command to execute to show a live demo of the result to the user. For example, use \`open index.html\` to display a created html website, or \`open localhost:3000\` to display a locally running development server. But DO NOT use commands like \`echo\` or \`cat\` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions",
usage: "Your command here (optional)",
},
// Different than the vanilla ASK_PROGRESS_PARAMETER
{
name: "task_progress",
required: false,
@@ -1,4 +1,3 @@
import { z } from "zod"
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
@@ -19,46 +18,43 @@ const generic: ClineToolSpec = {
{
name: "action",
required: true,
instruction:
"The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**. - Example: `<action>close</action>`",
instruction: `The action to perform. The available actions are:
* launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**.
- Use with the \`url\` parameter to provide the URL.
- Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.)
* click: Click at a specific x,y coordinate.
- Use with the \`coordinate\` parameter to specify the location.
- Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot.
* type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text.
- Use with the \`text\` parameter to provide the string to type.
* scroll_down: Scroll down the page by one page height.
* scroll_up: Scroll up the page by one page height.
* close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.
- Example: \`<action>close</action>\``,
usage: "Action to perform (e.g., launch, click, type, scroll_down, scroll_up, close)",
},
{
name: "url",
required: false,
instruction: "Use this for providing the URL for the `launch` action. * Example: <url>https://example.com</url>",
instruction: `Use this for providing the URL for the \`launch\` action.
* Example: <url>https://example.com</url>`,
usage: "URL to launch the browser at (optional)",
},
{
name: "coordinate",
required: false,
instruction: `The X and Y coordinates for the \`click\` action. Coordinates should be within the **{{BROWSER_VIEWPORT_WIDTH}}x{{BROWSER_VIEWPORT_HEIGHT}}** resolution. * Example: <coordinate>450,300</coordinate>`,
instruction: `The X and Y coordinates for the \`click\` action. Coordinates should be within the **{{BROWSER_VIEWPORT_WIDTH}}x{{BROWSER_VIEWPORT_HEIGHT}}** resolution.
* Example: <coordinate>450,300</coordinate>`,
usage: "x,y coordinates (optional)",
},
{
name: "text",
required: false,
instruction: "Use this for providing the text for the `type` action. * Example: <text>Hello, world!</text>",
instruction: `Use this for providing the text for the \`type\` action.
* Example: <text>Hello, world!</text>`,
usage: "Text to type (optional)",
},
],
}
export const browser_action_zod_schema = z.object({
action: z
.enum(["launch", "click", "type", "scroll_down", "scroll_up", "close"])
.describe(
"The action to perform. The available actions are: * launch: Launch a new Puppeteer-controlled browser instance at the specified URL. This **must always be the first action**. - Use with the `url` parameter to provide the URL. - Ensure the URL is valid and includes the appropriate protocol (e.g. http://localhost:3000/page, file:///path/to/file.html, etc.) * click: Click at a specific x,y coordinate. - Use with the `coordinate` parameter to specify the location. - Always click in the center of an element (icon, button, link, etc.) based on coordinates derived from a screenshot. * type: Type a string of text on the keyboard. You might use this after clicking on a text field to input text. - Use with the `text` parameter to provide the string to type. * scroll_down: Scroll down the page by one page height. * scroll_up: Scroll up the page by one page height. * close: Close the Puppeteer-controlled browser instance. This **must always be the final browser action**.",
),
url: z.string().url().optional().describe("Use this for providing the URL for the `launch` action."),
coordinate: z
.string()
.regex(/^\d+,\d+$/)
.optional()
.describe(
"The X and Y coordinates for the `click` action. Coordinates should be within the **{{BROWSER_VIEWPORT_WIDTH}}x{{BROWSER_VIEWPORT_HEIGHT}}** resolution. * Example: <coordinate>450,300</coordinate>",
),
text: z.string().max(1000).optional().describe("Use this for providing the text for the `type` action."),
})
export const browser_action_variants = [generic]
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const generic: ClineToolSpec = {
variant: ModelFamily.GENERIC,
@@ -11,13 +12,14 @@ const generic: ClineToolSpec = {
{
name: "command",
required: true,
instruction: "The CLI command to execute...",
instruction: `The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.`,
usage: "Your command here",
},
{
name: "requires_approval",
required: true,
instruction: "A boolean indicating whether...",
instruction:
"A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.",
usage: "true or false",
},
],
@@ -41,6 +43,7 @@ const gpt = {
required: false,
instruction: "Whether the command is dangerous. If true, user will be asked to confirm.",
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const id = ClineDefaultTool.LIST_CODE_DEF
@@ -17,6 +18,7 @@ const generic: ClineToolSpec = {
instruction: `The path of the directory (relative to the current working directory {{CWD}}) to list top level source code definitions for.`,
usage: "Directory path here",
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const id = ClineDefaultTool.LIST_FILES
@@ -23,6 +24,7 @@ const generic: ClineToolSpec = {
instruction: "Whether to list files recursively. Use true for recursive listing, false or omit for top-level only.",
usage: "true or false (optional)",
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -17,7 +17,11 @@ const generic: ClineToolSpec = {
id,
variant: ModelFamily.GENERIC,
name: "load_mcp_documentation",
description: `Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with \`use_mcp_tool\` and \`access_mcp_resource\`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.`,
description: `Load documentation about creating MCP servers. This tool should be used when the user requests to create or install an MCP server (the user may ask you something along the lines of "add a tool" that does some function, in other words to create an MCP server that provides tools and resources that may connect to external APIs for example. You have the ability to create an MCP server and add it to a configuration file that will then expose the tools and resources for you to use with \`use_mcp_tool\` and \`access_mcp_resource\`). The documentation provides detailed information about the MCP server creation process, including setup instructions, best practices, and examples.
Parameters: None
Usage:
<load_mcp_documentation>
</load_mcp_documentation>`,
contextRequirements: (context) => context.mcpHub !== undefined && context.mcpHub !== null,
}
@@ -25,7 +25,7 @@ const generic: ClineToolSpec = {
variant: ModelFamily.GENERIC,
id,
name: "new_task",
description: ` Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
description: `Request to create a new task with preloaded context covering the conversation with the user up to this point and key information for continuing with the new task. With this tool, you will create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions, with a focus on the most relevant information required for the new task.
Among other important areas of focus, this summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the new task. The user will be presented with a preview of your generated context and can choose to create a new task or keep chatting in the current conversation. The user may choose to start a new task at any point.`,
parameters: [
{
@@ -42,12 +42,13 @@ However, if while writing your response you realize you actually need to do more
"Set to true if while formulating your response that you found you need to do more exploration with tools, for example reading files. (Remember, you can explore the project with tools like read_file in PLAN MODE without the user having to toggle to ACT MODE.) Defaults to false if not specified.",
usage: "true or false (optional, but you MUST set to true if in <response> you need to read files or use other exploration tools)",
},
// Different than the vanilla TASK_PROGRESS_PARAMETER
{
name: "task_progress",
required: false,
instruction:
" A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)",
usage: "Checklist here (optional)",
usage: "Checklist here (If you have presented the user with concrete steps or requirements, you can optionally include a todo list outlining these steps.)",
dependencies: [ClineDefaultTool.TODO],
},
],
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const id = ClineDefaultTool.FILE_READ
@@ -17,13 +18,7 @@ const generic: ClineToolSpec = {
instruction: `The path of the file to read (relative to the current working directory {{CWD}})`,
usage: "File path here",
},
{
name: "task_progress",
required: false,
instruction: `A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)`,
usage: "Checklist here (optional)",
dependencies: [ClineDefaultTool.TODO],
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const id = ClineDefaultTool.FILE_EDIT
@@ -46,13 +47,7 @@ const generic: ClineToolSpec = {
* To delete code: Use empty REPLACE section`,
usage: "Search and replace blocks here",
},
{
name: "task_progress",
required: false,
instruction: `A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)`,
usage: "Checklist here (optional)",
dependencies: [ClineDefaultTool.TODO],
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
/**
* ## search_files
@@ -45,6 +46,7 @@ const generic: ClineToolSpec = {
"Glob pattern to filter files (e.g., '*.ts' for TypeScript files). If not provided, it will search all files (*).",
usage: "file pattern here (optional)",
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
/**
## use_mcp_tool
@@ -54,20 +55,14 @@ const generic: ClineToolSpec = {
name: "arguments",
required: true,
instruction: "A JSON object containing the tool's input parameters, following the tool's input schema",
usage: `{
usage: `
{
"param1": "value1",
"param2": "value2"
}`,
dependencies: [ClineDefaultTool.MCP_USE],
},
{
name: "task_progress",
required: false,
instruction:
" A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)",
usage: "Checklist here (optional)",
dependencies: [ClineDefaultTool.TODO],
}
`,
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
const nextGen: ClineToolSpec = {
variant: ModelFamily.NEXT_GEN,
@@ -21,6 +22,7 @@ const nextGen: ClineToolSpec = {
instruction: "The URL to fetch content from",
usage: "https://example.com/docs",
},
TASK_PROGRESS_PARAMETER,
],
}
@@ -1,6 +1,7 @@
import { ModelFamily } from "@/shared/prompts"
import { ClineDefaultTool } from "@/shared/tools"
import type { ClineToolSpec } from "../spec"
import { TASK_PROGRESS_PARAMETER } from "../types"
/**
* ## write_to_file
@@ -43,14 +44,7 @@ const generic: ClineToolSpec = {
"The content to write to the file. ALWAYS provide the COMPLETE intended content of the file, without any truncation or omissions. You MUST include ALL parts of the file, even if they haven't been modified.",
usage: "Your file content here",
},
{
name: "task_progress",
required: false,
instruction:
"A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)",
usage: "Checklist here (optional)",
dependencies: [ClineDefaultTool.TODO],
},
TASK_PROGRESS_PARAMETER,
],
}
+12 -1
View File
@@ -2,7 +2,7 @@
* Enhanced type definitions for better type safety and developer experience
*/
import { ApiHandlerModel, ApiProviderInfo } from "@/core/api"
import { ApiProviderInfo } from "@/core/api"
import type { McpHub } from "@/services/mcp/McpHub"
import type { BrowserSettings } from "@/shared/BrowserSettings"
import type { FocusChainSettings } from "@/shared/FocusChainSettings"
@@ -239,3 +239,14 @@ export interface VariantSchema {
readonly optional: readonly string[]
readonly validation: Record<string, (value: unknown) => boolean>
}
/**
* Common parameter shared between tools for tracking task progress
*/
export const TASK_PROGRESS_PARAMETER = {
name: "task_progress",
required: false,
instruction: `A checklist showing task progress after this tool use is completed. (See 'Updating Task Progress' section for more details)`,
usage: "Checklist here (optional)",
dependencies: [ClineDefaultTool.TODO],
}
@@ -1,4 +1,4 @@
import { SystemPromptSection } from "../.."
import { SystemPromptSection } from "../../templates/placeholders"
export const baseTemplate = `{{${SystemPromptSection.AGENT_ROLE}}}
@@ -1,4 +1,4 @@
import { SystemPromptSection } from "../.."
import { SystemPromptSection } from "../../templates/placeholders"
export const baseTemplate = `{{${SystemPromptSection.AGENT_ROLE}}}
@@ -7,34 +7,39 @@
*/
export { config as genericConfig, type GenericVariantConfig } from "./generic/config"
export { config as gpt5Config, type GPT5VariantConfig } from "./gpt-5/config"
export { config as nextGenConfig, type NextGenVariantConfig } from "./next-gen/config"
export { config as xsConfig, type XsVariantConfig } from "./xs/config"
import { config as genericConfig } from "./generic/config"
import { config as gpt5Config } from "./gpt-5/config"
import { config as nextGenConfig } from "./next-gen/config"
import { config as xsConfig } from "./xs/config"
/**
* Variant Registry for dynamic loading
*
* This registry allows for lazy loading of variant configurations,
* which is useful for reducing initial bundle size and enabling
* runtime variant selection.
* This registry allows for loading variant configurations.
*/
export const VARIANT_CONFIGS = {
/**
* Generic variant - Fallback for all model types
* Optimized for broad compatibility and stable performance
*/
generic: () => import("./generic/config").then((m) => m.config),
generic: genericConfig,
/**
* Next-gen variant - Advanced models with enhanced capabilities
* Includes additional features like feedback loops and web fetching
*/
"next-gen": () => import("./next-gen/config").then((m) => m.config),
"next-gen": nextGenConfig,
gpt5: gpt5Config,
/**
* XS variant - Compact models with limited context windows
* Streamlined for efficiency with essential tools only
*/
xs: () => import("./xs/config").then((m) => m.config),
xs: xsConfig,
} as const
/**
@@ -60,18 +65,16 @@ export function isValidVariantId(id: string): id is VariantId {
/**
* Load a variant configuration dynamically
* @param variantId - The ID of the variant to load
* @returns Promise that resolves to the variant configuration
* @returns Variant configuration
*/
export async function loadVariantConfig(variantId: VariantId) {
const loader = VARIANT_CONFIGS[variantId]
return await loader()
export function loadVariantConfig(variantId: VariantId) {
return VARIANT_CONFIGS[variantId]
}
/**
* Load all variant configurations
* @returns Promise that resolves to a map of all variant configurations
* @returns A map of all variant configurations
*/
export async function loadAllVariantConfigs() {
const entries = await Promise.all(Object.entries(VARIANT_CONFIGS).map(async ([id, loader]) => [id, await loader()] as const))
return Object.fromEntries(entries) as Record<VariantId, Awaited<ReturnType<(typeof VARIANT_CONFIGS)[VariantId]>>>
export function loadAllVariantConfigs() {
return VARIANT_CONFIGS
}
@@ -1,4 +1,4 @@
import { SystemPromptSection } from "../.."
import { SystemPromptSection } from "../../templates/placeholders"
export const baseTemplate = `{{${SystemPromptSection.AGENT_ROLE}}}
@@ -1,4 +1,5 @@
import { PromptVariant, SystemPromptSection } from "../.."
import { SystemPromptSection } from "../../templates/placeholders"
import { PromptVariant } from "../../types"
const XS_EDITING_FILES = `FILE EDITING RULES
- Default: replace_in_file; write_to_file for new files or full rewrites.
+1 -1
View File
@@ -1,6 +1,6 @@
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { ClineRulesToggles } from "@shared/cline-rules"
import fs from "fs/promises"
import { telemetryService } from "@/services/telemetry"
import {
condenseToolResponse,
deepPlanningToolResponse,
+11 -7
View File
@@ -1,5 +1,6 @@
import { ApiConfiguration, fireworksDefaultModelId } from "@shared/api"
import type { ExtensionContext } from "vscode"
import { writeTaskHistoryToState } from "./disk"
import { STATE_MANAGER_NOT_INITIALIZED } from "./error-messages"
import { GlobalState, GlobalStateKey, LocalState, LocalStateKey, SecretKey, Secrets } from "./state-keys"
import { readGlobalStateFromDisk, readSecretsFromDisk, readWorkspaceStateFromDisk } from "./utils/state-helpers"
@@ -46,13 +47,13 @@ export class StateManager {
const secrets = await readSecretsFromDisk(this.context)
const workspaceState = await readWorkspaceStateFromDisk(this.context)
// Populate the caches with all extension state fields
// Populate the cache with all extension state and secrets fields
// Use populate method to avoid triggering persistence during initialization
this.populateCache(globalState, secrets, workspaceState)
this.isInitialized = true
} catch (error) {
console.error("Failed to initialize StateManager:", error)
console.error("[StateManager] Failed to initialize:", error)
throw error
}
}
@@ -550,11 +551,11 @@ export class StateManager {
this.pendingWorkspaceState.clear()
this.persistenceTimeout = null
} catch (error) {
console.error("Failed to persist pending changes:", error)
console.error("[StateManager] Failed to persist pending changes:", error)
this.persistenceTimeout = null
// Call persistence error callback for error recovery
this.onPersistenceError?.({ error: error as Error })
this.onPersistenceError?.({ error: error })
}
}, this.PERSISTENCE_DELAY_MS)
}
@@ -566,12 +567,15 @@ export class StateManager {
try {
await Promise.all(
Array.from(keys).map((key) => {
const value = this.globalStateCache[key]
return this.context.globalState.update(key, value)
if (key === "taskHistory") {
// Route task history persistence to file, not VS Code globalState
return writeTaskHistoryToState(this.context, this.globalStateCache[key])
}
return this.context.globalState.update(key, this.globalStateCache[key])
}),
)
} catch (error) {
console.error("Failed to persist global state batch:", error)
console.error("[StateManager] Failed to persist global state batch:", error)
throw error
}
}
+40
View File
@@ -2,6 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
import { TaskMetadata } from "@core/context/context-tracking/ContextTrackerTypes"
import { execa } from "@packages/execa"
import { ClineMessage } from "@shared/ExtensionMessage"
import { HistoryItem } from "@shared/HistoryItem"
import { fileExistsAtPath } from "@utils/fs"
import fs from "fs/promises"
import os from "os"
@@ -180,3 +181,42 @@ export async function saveTaskMetadata(context: vscode.ExtensionContext, taskId:
console.error("Failed to save task metadata:", error)
}
}
export async function ensureStateDirectoryExists(context: vscode.ExtensionContext): Promise<string> {
const stateDir = path.join(context.globalStorageUri.fsPath, "state")
await fs.mkdir(stateDir, { recursive: true })
return stateDir
}
export async function getTaskHistoryStateFilePath(context: vscode.ExtensionContext): Promise<string> {
return path.join(await ensureStateDirectoryExists(context), "taskHistory.json")
}
export async function taskHistoryStateFileExists(context: vscode.ExtensionContext): Promise<boolean> {
const filePath = await getTaskHistoryStateFilePath(context)
return fileExistsAtPath(filePath)
}
export async function readTaskHistoryFromState(context: vscode.ExtensionContext): Promise<HistoryItem[]> {
try {
const filePath = await getTaskHistoryStateFilePath(context)
if (await fileExistsAtPath(filePath)) {
return JSON.parse(await fs.readFile(filePath, "utf8"))
}
return []
} catch (error) {
console.error("[Disk] Failed to read task history:", error)
throw error
}
}
export async function writeTaskHistoryToState(context: vscode.ExtensionContext, items: HistoryItem[]): Promise<void> {
try {
const filePath = await getTaskHistoryStateFilePath(context)
// Always create the file; if items is empty, write [] to ensure presence on first startup
await fs.writeFile(filePath, JSON.stringify(items))
} catch (error) {
console.error("[Disk] Failed to write task history:", error)
throw error
}
}
+22 -1
View File
@@ -1,7 +1,7 @@
import fs from "fs/promises"
import path from "path"
import * as vscode from "vscode"
import { ensureRulesDirectoryExists } from "./disk"
import { ensureRulesDirectoryExists, readTaskHistoryFromState, writeTaskHistoryToState } from "./disk"
import { StateManager } from "./StateManager"
export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionContext) {
@@ -66,6 +66,27 @@ export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionC
}
}
export async function migrateTaskHistoryToFile(context: vscode.ExtensionContext) {
try {
// If the old taskHistory vs code global state is undefined, do nothing
const vscodeGlobalStateTaskHistory = await context.globalState.get("taskHistory")
if (vscodeGlobalStateTaskHistory === undefined) {
return
}
// Read legacy from VS Code globalState, default to []
console.log("[Storage Migration] taskHistory from vscode global state: ", vscodeGlobalStateTaskHistory)
// Always create the file, even when empty
await writeTaskHistoryToState(context, Array.isArray(vscodeGlobalStateTaskHistory) ? vscodeGlobalStateTaskHistory : [])
// Don't remove the old taskHistory yet, while this version is not in production, for better dev experience.
// This is because the old version of the code (still in prod) is still reading taskHistory from the vs code global state, so it will appear as if all the user's tasks have been deleted.
// await context.globalState.update("taskHistory", undefined)
console.log("[Storage Migration] taskHistory file in new location: ", await readTaskHistoryFromState(context))
console.log("[Storage Migration] old vscode global state: ", await context.globalState.get("taskHistory"))
} catch (error) {
console.error("[Storage Migration] Failed to migrate task history to file:", error)
}
}
export async function migrateMcpMarketplaceEnableSetting(mcpMarketplaceEnabledRaw: boolean | undefined): Promise<boolean> {
const config = vscode.workspace.getConfiguration("cline")
const mcpMarketplaceEnabled = config.get<boolean>("mcpMarketplace.enabled")
+310 -293
View File
@@ -5,12 +5,11 @@ import { AutoApprovalSettings, DEFAULT_AUTO_APPROVAL_SETTINGS } from "@/shared/A
import { BrowserSettings, DEFAULT_BROWSER_SETTINGS } from "@/shared/BrowserSettings"
import { ClineRulesToggles } from "@/shared/cline-rules"
import { DEFAULT_FOCUS_CHAIN_SETTINGS, FocusChainSettings } from "@/shared/FocusChainSettings"
import { HistoryItem } from "@/shared/HistoryItem"
import { DEFAULT_MCP_DISPLAY_MODE, McpDisplayMode } from "@/shared/McpDisplayMode"
import { McpMarketplaceCatalog } from "@/shared/mcp"
import { Mode, OpenaiReasoningEffort } from "@/shared/storage/types"
import { TelemetrySetting } from "@/shared/TelemetrySetting"
import { UserInfo } from "@/shared/UserInfo"
import { readTaskHistoryFromState } from "../disk"
import { GlobalState, LocalState, SecretKey, Secrets } from "../state-keys"
export async function readSecretsFromDisk(context: ExtensionContext): Promise<Secrets> {
@@ -142,303 +141,321 @@ export async function readWorkspaceStateFromDisk(context: ExtensionContext): Pro
}
export async function readGlobalStateFromDisk(context: ExtensionContext): Promise<GlobalState> {
// Get all global state values
const strictPlanModeEnabled = context.globalState.get("strictPlanModeEnabled") as boolean | undefined
const useAutoCondense = context.globalState.get("useAutoCondense") as boolean | undefined
const isNewUser = context.globalState.get("isNewUser") as boolean | undefined
const welcomeViewCompleted = context.globalState.get("welcomeViewCompleted") as boolean | undefined
const awsRegion = context.globalState.get("awsRegion") as string | undefined
const awsUseCrossRegionInference = context.globalState.get("awsUseCrossRegionInference") as boolean | undefined
const awsBedrockUsePromptCache = context.globalState.get("awsBedrockUsePromptCache") as boolean | undefined
const awsBedrockEndpoint = context.globalState.get("awsBedrockEndpoint") as string | undefined
const awsProfile = context.globalState.get("awsProfile") as string | undefined
const awsUseProfile = context.globalState.get("awsUseProfile") as boolean | undefined
const awsAuthentication = context.globalState.get("awsAuthentication") as string | undefined
const vertexProjectId = context.globalState.get("vertexProjectId") as string | undefined
const vertexRegion = context.globalState.get("vertexRegion") as string | undefined
const openAiBaseUrl = context.globalState.get("openAiBaseUrl") as string | undefined
const requestyBaseUrl = context.globalState.get("requestyBaseUrl") as string | undefined
const openAiHeaders = context.globalState.get("openAiHeaders") as Record<string, string> | undefined
const ollamaBaseUrl = context.globalState.get("ollamaBaseUrl") as string | undefined
const ollamaApiOptionsCtxNum = context.globalState.get("ollamaApiOptionsCtxNum") as string | undefined
const lmStudioBaseUrl = context.globalState.get("lmStudioBaseUrl") as string | undefined
const lmStudioMaxTokens = context.globalState.get("lmStudioMaxTokens") as string | undefined
const anthropicBaseUrl = context.globalState.get("anthropicBaseUrl") as string | undefined
const geminiBaseUrl = context.globalState.get("geminiBaseUrl") as string | undefined
const azureApiVersion = context.globalState.get("azureApiVersion") as string | undefined
const openRouterProviderSorting = context.globalState.get("openRouterProviderSorting") as string | undefined
const lastShownAnnouncementId = context.globalState.get("lastShownAnnouncementId") as string | undefined
const taskHistory = context.globalState.get("taskHistory") as HistoryItem[] | undefined
const autoApprovalSettings = context.globalState.get("autoApprovalSettings") as AutoApprovalSettings | undefined
const browserSettings = context.globalState.get("browserSettings") as BrowserSettings | undefined
const liteLlmBaseUrl = context.globalState.get("liteLlmBaseUrl") as string | undefined
const liteLlmUsePromptCache = context.globalState.get("liteLlmUsePromptCache") as boolean | undefined
const fireworksModelMaxCompletionTokens = context.globalState.get("fireworksModelMaxCompletionTokens") as number | undefined
const fireworksModelMaxTokens = context.globalState.get("fireworksModelMaxTokens") as number | undefined
const userInfo = context.globalState.get("userInfo") as UserInfo | undefined
const qwenApiLine = context.globalState.get("qwenApiLine") as string | undefined
const moonshotApiLine = context.globalState.get("moonshotApiLine") as string | undefined
const zaiApiLine = context.globalState.get("zaiApiLine") as string | undefined
const telemetrySetting = context.globalState.get("telemetrySetting") as TelemetrySetting | undefined
const asksageApiUrl = context.globalState.get("asksageApiUrl") as string | undefined
const planActSeparateModelsSettingRaw = context.globalState.get("planActSeparateModelsSetting") as boolean | undefined
const favoritedModelIds = context.globalState.get("favoritedModelIds") as string[] | undefined
const globalClineRulesToggles = context.globalState.get("globalClineRulesToggles") as ClineRulesToggles | undefined
const requestTimeoutMs = context.globalState.get("requestTimeoutMs") as number | undefined
const shellIntegrationTimeout = context.globalState.get("shellIntegrationTimeout") as number | undefined
const enableCheckpointsSettingRaw = context.globalState.get("enableCheckpointsSetting") as boolean | undefined
const mcpMarketplaceEnabledRaw = context.globalState.get("mcpMarketplaceEnabled") as boolean | undefined
const mcpDisplayMode = context.globalState.get("mcpDisplayMode") as McpDisplayMode | undefined
const mcpResponsesCollapsedRaw = context.globalState.get("mcpResponsesCollapsed") as boolean | undefined
const globalWorkflowToggles = context.globalState.get("globalWorkflowToggles") as ClineRulesToggles | undefined
const terminalReuseEnabled = context.globalState.get("terminalReuseEnabled") as boolean | undefined
const terminalOutputLineLimit = context.globalState.get("terminalOutputLineLimit") as number | undefined
const defaultTerminalProfile = context.globalState.get("defaultTerminalProfile") as string | undefined
const sapAiCoreBaseUrl = context.globalState.get("sapAiCoreBaseUrl") as string | undefined
const sapAiCoreTokenUrl = context.globalState.get("sapAiCoreTokenUrl") as string | undefined
const sapAiResourceGroup = context.globalState.get("sapAiResourceGroup") as string | undefined
const claudeCodePath = context.globalState.get("claudeCodePath") as string | undefined
const difyBaseUrl = context.globalState.get("difyBaseUrl") as string | undefined
const openaiReasoningEffort = context.globalState.get("openaiReasoningEffort") as OpenaiReasoningEffort | undefined
const preferredLanguage = context.globalState.get("preferredLanguage") as string | undefined
const focusChainSettings = context.globalState.get("focusChainSettings") as FocusChainSettings | undefined
const focusChainFeatureFlagEnabled = context.globalState.get("focusChainFeatureFlagEnabled") as boolean | undefined
try {
// Get all global state values
const strictPlanModeEnabled = context.globalState.get("strictPlanModeEnabled") as boolean | undefined
const useAutoCondense = context.globalState.get("useAutoCondense") as boolean | undefined
const isNewUser = context.globalState.get("isNewUser") as boolean | undefined
const welcomeViewCompleted = context.globalState.get("welcomeViewCompleted") as boolean | undefined
const awsRegion = context.globalState.get("awsRegion") as string | undefined
const awsUseCrossRegionInference = context.globalState.get("awsUseCrossRegionInference") as boolean | undefined
const awsBedrockUsePromptCache = context.globalState.get("awsBedrockUsePromptCache") as boolean | undefined
const awsBedrockEndpoint = context.globalState.get("awsBedrockEndpoint") as string | undefined
const awsProfile = context.globalState.get("awsProfile") as string | undefined
const awsUseProfile = context.globalState.get("awsUseProfile") as boolean | undefined
const awsAuthentication = context.globalState.get("awsAuthentication") as string | undefined
const vertexProjectId = context.globalState.get("vertexProjectId") as string | undefined
const vertexRegion = context.globalState.get("vertexRegion") as string | undefined
const openAiBaseUrl = context.globalState.get("openAiBaseUrl") as string | undefined
const requestyBaseUrl = context.globalState.get("requestyBaseUrl") as string | undefined
const openAiHeaders = context.globalState.get("openAiHeaders") as Record<string, string> | undefined
const ollamaBaseUrl = context.globalState.get("ollamaBaseUrl") as string | undefined
const ollamaApiOptionsCtxNum = context.globalState.get("ollamaApiOptionsCtxNum") as string | undefined
const lmStudioBaseUrl = context.globalState.get("lmStudioBaseUrl") as string | undefined
const lmStudioMaxTokens = context.globalState.get("lmStudioMaxTokens") as string | undefined
const anthropicBaseUrl = context.globalState.get("anthropicBaseUrl") as string | undefined
const geminiBaseUrl = context.globalState.get("geminiBaseUrl") as string | undefined
const azureApiVersion = context.globalState.get("azureApiVersion") as string | undefined
const openRouterProviderSorting = context.globalState.get("openRouterProviderSorting") as string | undefined
const lastShownAnnouncementId = context.globalState.get("lastShownAnnouncementId") as string | undefined
const autoApprovalSettings = context.globalState.get("autoApprovalSettings") as AutoApprovalSettings | undefined
const browserSettings = context.globalState.get("browserSettings") as BrowserSettings | undefined
const liteLlmBaseUrl = context.globalState.get("liteLlmBaseUrl") as string | undefined
const liteLlmUsePromptCache = context.globalState.get("liteLlmUsePromptCache") as boolean | undefined
const fireworksModelMaxCompletionTokens = context.globalState.get("fireworksModelMaxCompletionTokens") as
| number
| undefined
const fireworksModelMaxTokens = context.globalState.get("fireworksModelMaxTokens") as number | undefined
const userInfo = context.globalState.get("userInfo") as UserInfo | undefined
const qwenApiLine = context.globalState.get("qwenApiLine") as string | undefined
const moonshotApiLine = context.globalState.get("moonshotApiLine") as string | undefined
const zaiApiLine = context.globalState.get("zaiApiLine") as string | undefined
const telemetrySetting = context.globalState.get("telemetrySetting") as TelemetrySetting | undefined
const asksageApiUrl = context.globalState.get("asksageApiUrl") as string | undefined
const planActSeparateModelsSettingRaw = context.globalState.get("planActSeparateModelsSetting") as boolean | undefined
const favoritedModelIds = context.globalState.get("favoritedModelIds") as string[] | undefined
const globalClineRulesToggles = context.globalState.get("globalClineRulesToggles") as ClineRulesToggles | undefined
const requestTimeoutMs = context.globalState.get("requestTimeoutMs") as number | undefined
const shellIntegrationTimeout = context.globalState.get("shellIntegrationTimeout") as number | undefined
const enableCheckpointsSettingRaw = context.globalState.get("enableCheckpointsSetting") as boolean | undefined
const mcpMarketplaceEnabledRaw = context.globalState.get("mcpMarketplaceEnabled") as boolean | undefined
const mcpDisplayMode = context.globalState.get("mcpDisplayMode") as McpDisplayMode | undefined
const mcpResponsesCollapsedRaw = context.globalState.get("mcpResponsesCollapsed") as boolean | undefined
const globalWorkflowToggles = context.globalState.get("globalWorkflowToggles") as ClineRulesToggles | undefined
const terminalReuseEnabled = context.globalState.get("terminalReuseEnabled") as boolean | undefined
const terminalOutputLineLimit = context.globalState.get("terminalOutputLineLimit") as number | undefined
const defaultTerminalProfile = context.globalState.get("defaultTerminalProfile") as string | undefined
const sapAiCoreBaseUrl = context.globalState.get("sapAiCoreBaseUrl") as string | undefined
const sapAiCoreTokenUrl = context.globalState.get("sapAiCoreTokenUrl") as string | undefined
const sapAiResourceGroup = context.globalState.get("sapAiResourceGroup") as string | undefined
const claudeCodePath = context.globalState.get("claudeCodePath") as string | undefined
const difyBaseUrl = context.globalState.get("difyBaseUrl") as string | undefined
const openaiReasoningEffort = context.globalState.get("openaiReasoningEffort") as OpenaiReasoningEffort | undefined
const preferredLanguage = context.globalState.get("preferredLanguage") as string | undefined
const focusChainSettings = context.globalState.get("focusChainSettings") as FocusChainSettings | undefined
const focusChainFeatureFlagEnabled = context.globalState.get("focusChainFeatureFlagEnabled") as boolean | undefined
const mcpMarketplaceCatalog = context.globalState.get("mcpMarketplaceCatalog") as GlobalState["mcpMarketplaceCatalog"]
const qwenCodeOauthPath = context.globalState.get("qwenCodeOauthPath") as GlobalState["qwenCodeOauthPath"]
const customPrompt = context.globalState.get("customPrompt") as GlobalState["customPrompt"]
const mcpMarketplaceCatalog = context.globalState.get("mcpMarketplaceCatalog") as GlobalState["mcpMarketplaceCatalog"]
const qwenCodeOauthPath = context.globalState.get("qwenCodeOauthPath") as GlobalState["qwenCodeOauthPath"]
const customPrompt = context.globalState.get("customPrompt") as GlobalState["customPrompt"]
// Get mode-related configurations
const mode = context.globalState.get("mode") as Mode | undefined
// Get mode-related configurations
const mode = context.globalState.get("mode") as Mode | undefined
// Plan mode configurations
const planModeApiProvider = context.globalState.get("planModeApiProvider") as ApiProvider | undefined
const planModeApiModelId = context.globalState.get("planModeApiModelId") as string | undefined
const planModeThinkingBudgetTokens = context.globalState.get("planModeThinkingBudgetTokens") as number | undefined
const planModeReasoningEffort = context.globalState.get("planModeReasoningEffort") as string | undefined
const planModeVsCodeLmModelSelector = context.globalState.get("planModeVsCodeLmModelSelector") as
| LanguageModelChatSelector
| undefined
const planModeAwsBedrockCustomSelected = context.globalState.get("planModeAwsBedrockCustomSelected") as boolean | undefined
const planModeAwsBedrockCustomModelBaseId = context.globalState.get("planModeAwsBedrockCustomModelBaseId") as
| BedrockModelId
| undefined
const planModeOpenRouterModelId = context.globalState.get("planModeOpenRouterModelId") as string | undefined
const planModeOpenRouterModelInfo = context.globalState.get("planModeOpenRouterModelInfo") as ModelInfo | undefined
const planModeOpenAiModelId = context.globalState.get("planModeOpenAiModelId") as string | undefined
const planModeOpenAiModelInfo = context.globalState.get("planModeOpenAiModelInfo") as ModelInfo | undefined
const planModeOllamaModelId = context.globalState.get("planModeOllamaModelId") as string | undefined
const planModeLmStudioModelId = context.globalState.get("planModeLmStudioModelId") as string | undefined
const planModeLiteLlmModelId = context.globalState.get("planModeLiteLlmModelId") as string | undefined
const planModeLiteLlmModelInfo = context.globalState.get("planModeLiteLlmModelInfo") as ModelInfo | undefined
const planModeRequestyModelId = context.globalState.get("planModeRequestyModelId") as string | undefined
const planModeRequestyModelInfo = context.globalState.get("planModeRequestyModelInfo") as ModelInfo | undefined
const planModeTogetherModelId = context.globalState.get("planModeTogetherModelId") as string | undefined
const planModeFireworksModelId = context.globalState.get("planModeFireworksModelId") as string | undefined
const planModeSapAiCoreModelId = context.globalState.get("planModeSapAiCoreModelId") as string | undefined
const planModeGroqModelId = context.globalState.get("planModeGroqModelId") as string | undefined
const planModeGroqModelInfo = context.globalState.get("planModeGroqModelInfo") as ModelInfo | undefined
const planModeHuggingFaceModelId = context.globalState.get("planModeHuggingFaceModelId") as string | undefined
const planModeHuggingFaceModelInfo = context.globalState.get("planModeHuggingFaceModelInfo") as ModelInfo | undefined
const planModeHuaweiCloudMaasModelId = context.globalState.get("planModeHuaweiCloudMaasModelId") as string | undefined
const planModeHuaweiCloudMaasModelInfo = context.globalState.get("planModeHuaweiCloudMaasModelInfo") as ModelInfo | undefined
const planModeBasetenModelId = context.globalState.get("planModeBasetenModelId") as string | undefined
const planModeBasetenModelInfo = context.globalState.get("planModeBasetenModelInfo") as ModelInfo | undefined
const planModeVercelAiGatewayModelId = context.globalState.get("planModeVercelAiGatewayModelId") as string | undefined
const planModeVercelAiGatewayModelInfo = context.globalState.get("planModeVercelAiGatewayModelInfo") as ModelInfo | undefined
// Act mode configurations
const actModeApiProvider = context.globalState.get("actModeApiProvider") as ApiProvider | undefined
const actModeApiModelId = context.globalState.get("actModeApiModelId") as string | undefined
const actModeThinkingBudgetTokens = context.globalState.get("actModeThinkingBudgetTokens") as number | undefined
const actModeReasoningEffort = context.globalState.get("actModeReasoningEffort") as string | undefined
const actModeVsCodeLmModelSelector = context.globalState.get("actModeVsCodeLmModelSelector") as
| LanguageModelChatSelector
| undefined
const actModeAwsBedrockCustomSelected = context.globalState.get("actModeAwsBedrockCustomSelected") as boolean | undefined
const actModeAwsBedrockCustomModelBaseId = context.globalState.get("actModeAwsBedrockCustomModelBaseId") as
| BedrockModelId
| undefined
const actModeOpenRouterModelId = context.globalState.get("actModeOpenRouterModelId") as string | undefined
const actModeOpenRouterModelInfo = context.globalState.get("actModeOpenRouterModelInfo") as ModelInfo | undefined
const actModeOpenAiModelId = context.globalState.get("actModeOpenAiModelId") as string | undefined
const actModeOpenAiModelInfo = context.globalState.get("actModeOpenAiModelInfo") as ModelInfo | undefined
const actModeOllamaModelId = context.globalState.get("actModeOllamaModelId") as string | undefined
const actModeLmStudioModelId = context.globalState.get("actModeLmStudioModelId") as string | undefined
const actModeLiteLlmModelId = context.globalState.get("actModeLiteLlmModelId") as string | undefined
const actModeLiteLlmModelInfo = context.globalState.get("actModeLiteLlmModelInfo") as ModelInfo | undefined
const actModeRequestyModelId = context.globalState.get("actModeRequestyModelId") as string | undefined
const actModeRequestyModelInfo = context.globalState.get("actModeRequestyModelInfo") as ModelInfo | undefined
const actModeTogetherModelId = context.globalState.get("actModeTogetherModelId") as string | undefined
const actModeFireworksModelId = context.globalState.get("actModeFireworksModelId") as string | undefined
const actModeSapAiCoreModelId = context.globalState.get("actModeSapAiCoreModelId") as string | undefined
const actModeGroqModelId = context.globalState.get("actModeGroqModelId") as string | undefined
const actModeGroqModelInfo = context.globalState.get("actModeGroqModelInfo") as ModelInfo | undefined
const actModeHuggingFaceModelId = context.globalState.get("actModeHuggingFaceModelId") as string | undefined
const actModeHuggingFaceModelInfo = context.globalState.get("actModeHuggingFaceModelInfo") as ModelInfo | undefined
const actModeHuaweiCloudMaasModelId = context.globalState.get("actModeHuaweiCloudMaasModelId") as string | undefined
const actModeHuaweiCloudMaasModelInfo = context.globalState.get("actModeHuaweiCloudMaasModelInfo") as ModelInfo | undefined
const actModeBasetenModelId = context.globalState.get("actModeBasetenModelId") as string | undefined
const actModeBasetenModelInfo = context.globalState.get("actModeBasetenModelInfo") as ModelInfo | undefined
const actModeVercelAiGatewayModelId = context.globalState.get("actModeVercelAiGatewayModelId") as string | undefined
const actModeVercelAiGatewayModelInfo = context.globalState.get("actModeVercelAiGatewayModelInfo") as ModelInfo | undefined
const sapAiCoreUseOrchestrationMode = context.globalState.get("sapAiCoreUseOrchestrationMode") as boolean | undefined
let apiProvider: ApiProvider
if (planModeApiProvider) {
apiProvider = planModeApiProvider
} else {
// New users should default to openrouter, since they've opted to use an API key instead of signing in
apiProvider = "openrouter"
}
const mcpResponsesCollapsed = mcpResponsesCollapsedRaw ?? false
// Plan/Act separate models setting is a boolean indicating whether the user wants to use different models for plan and act. Existing users expect this to be enabled, while we want new users to opt in to this being disabled by default.
// On win11 state sometimes initializes as empty string instead of undefined
let planActSeparateModelsSetting: boolean | undefined
if (planActSeparateModelsSettingRaw === true || planActSeparateModelsSettingRaw === false) {
planActSeparateModelsSetting = planActSeparateModelsSettingRaw
} else {
// default to true for existing users
if (planModeApiProvider) {
planActSeparateModelsSetting = true
} else {
// default to false for new users
planActSeparateModelsSetting = false
}
}
return {
// api configuration fields
claudeCodePath,
awsRegion,
awsUseCrossRegionInference,
awsBedrockUsePromptCache,
awsBedrockEndpoint,
awsProfile,
awsUseProfile,
awsAuthentication,
vertexProjectId,
vertexRegion,
openAiBaseUrl,
requestyBaseUrl,
openAiHeaders: openAiHeaders || {},
ollamaBaseUrl,
ollamaApiOptionsCtxNum,
lmStudioBaseUrl,
lmStudioMaxTokens,
anthropicBaseUrl,
geminiBaseUrl,
qwenApiLine,
moonshotApiLine,
zaiApiLine,
azureApiVersion,
openRouterProviderSorting,
liteLlmBaseUrl,
liteLlmUsePromptCache,
fireworksModelMaxCompletionTokens,
fireworksModelMaxTokens,
asksageApiUrl,
favoritedModelIds,
requestTimeoutMs,
sapAiCoreBaseUrl,
sapAiCoreTokenUrl,
sapAiResourceGroup,
difyBaseUrl,
sapAiCoreUseOrchestrationMode,
// Plan mode configurations
planModeApiProvider: planModeApiProvider || apiProvider,
planModeApiModelId,
planModeThinkingBudgetTokens,
planModeReasoningEffort,
planModeVsCodeLmModelSelector,
planModeAwsBedrockCustomSelected,
planModeAwsBedrockCustomModelBaseId,
planModeOpenRouterModelId,
planModeOpenRouterModelInfo,
planModeOpenAiModelId,
planModeOpenAiModelInfo,
planModeOllamaModelId,
planModeLmStudioModelId,
planModeLiteLlmModelId,
planModeLiteLlmModelInfo,
planModeRequestyModelId,
planModeRequestyModelInfo,
planModeTogetherModelId,
planModeFireworksModelId,
planModeSapAiCoreModelId,
planModeGroqModelId,
planModeGroqModelInfo,
planModeHuggingFaceModelId,
planModeHuggingFaceModelInfo,
planModeHuaweiCloudMaasModelId,
planModeHuaweiCloudMaasModelInfo,
planModeBasetenModelId,
planModeBasetenModelInfo,
planModeVercelAiGatewayModelId,
planModeVercelAiGatewayModelInfo,
const planModeApiProvider = context.globalState.get("planModeApiProvider") as ApiProvider | undefined
const planModeApiModelId = context.globalState.get("planModeApiModelId") as string | undefined
const planModeThinkingBudgetTokens = context.globalState.get("planModeThinkingBudgetTokens") as number | undefined
const planModeReasoningEffort = context.globalState.get("planModeReasoningEffort") as string | undefined
const planModeVsCodeLmModelSelector = context.globalState.get("planModeVsCodeLmModelSelector") as
| LanguageModelChatSelector
| undefined
const planModeAwsBedrockCustomSelected = context.globalState.get("planModeAwsBedrockCustomSelected") as
| boolean
| undefined
const planModeAwsBedrockCustomModelBaseId = context.globalState.get("planModeAwsBedrockCustomModelBaseId") as
| BedrockModelId
| undefined
const planModeOpenRouterModelId = context.globalState.get("planModeOpenRouterModelId") as string | undefined
const planModeOpenRouterModelInfo = context.globalState.get("planModeOpenRouterModelInfo") as ModelInfo | undefined
const planModeOpenAiModelId = context.globalState.get("planModeOpenAiModelId") as string | undefined
const planModeOpenAiModelInfo = context.globalState.get("planModeOpenAiModelInfo") as ModelInfo | undefined
const planModeOllamaModelId = context.globalState.get("planModeOllamaModelId") as string | undefined
const planModeLmStudioModelId = context.globalState.get("planModeLmStudioModelId") as string | undefined
const planModeLiteLlmModelId = context.globalState.get("planModeLiteLlmModelId") as string | undefined
const planModeLiteLlmModelInfo = context.globalState.get("planModeLiteLlmModelInfo") as ModelInfo | undefined
const planModeRequestyModelId = context.globalState.get("planModeRequestyModelId") as string | undefined
const planModeRequestyModelInfo = context.globalState.get("planModeRequestyModelInfo") as ModelInfo | undefined
const planModeTogetherModelId = context.globalState.get("planModeTogetherModelId") as string | undefined
const planModeFireworksModelId = context.globalState.get("planModeFireworksModelId") as string | undefined
const planModeSapAiCoreModelId = context.globalState.get("planModeSapAiCoreModelId") as string | undefined
const planModeGroqModelId = context.globalState.get("planModeGroqModelId") as string | undefined
const planModeGroqModelInfo = context.globalState.get("planModeGroqModelInfo") as ModelInfo | undefined
const planModeHuggingFaceModelId = context.globalState.get("planModeHuggingFaceModelId") as string | undefined
const planModeHuggingFaceModelInfo = context.globalState.get("planModeHuggingFaceModelInfo") as ModelInfo | undefined
const planModeHuaweiCloudMaasModelId = context.globalState.get("planModeHuaweiCloudMaasModelId") as string | undefined
const planModeHuaweiCloudMaasModelInfo = context.globalState.get("planModeHuaweiCloudMaasModelInfo") as
| ModelInfo
| undefined
const planModeBasetenModelId = context.globalState.get("planModeBasetenModelId") as string | undefined
const planModeBasetenModelInfo = context.globalState.get("planModeBasetenModelInfo") as ModelInfo | undefined
const planModeVercelAiGatewayModelId = context.globalState.get("planModeVercelAiGatewayModelId") as string | undefined
const planModeVercelAiGatewayModelInfo = context.globalState.get("planModeVercelAiGatewayModelInfo") as
| ModelInfo
| undefined
// Act mode configurations
actModeApiProvider: actModeApiProvider || apiProvider,
actModeApiModelId,
actModeThinkingBudgetTokens,
actModeReasoningEffort,
actModeVsCodeLmModelSelector,
actModeAwsBedrockCustomSelected,
actModeAwsBedrockCustomModelBaseId,
actModeOpenRouterModelId,
actModeOpenRouterModelInfo,
actModeOpenAiModelId,
actModeOpenAiModelInfo,
actModeOllamaModelId,
actModeLmStudioModelId,
actModeLiteLlmModelId,
actModeLiteLlmModelInfo,
actModeRequestyModelId,
actModeRequestyModelInfo,
actModeTogetherModelId,
actModeFireworksModelId,
actModeSapAiCoreModelId,
actModeGroqModelId,
actModeGroqModelInfo,
actModeHuggingFaceModelId,
actModeHuggingFaceModelInfo,
actModeHuaweiCloudMaasModelId,
actModeHuaweiCloudMaasModelInfo,
actModeBasetenModelId,
actModeBasetenModelInfo,
actModeVercelAiGatewayModelId,
actModeVercelAiGatewayModelInfo,
const actModeApiProvider = context.globalState.get("actModeApiProvider") as ApiProvider | undefined
const actModeApiModelId = context.globalState.get("actModeApiModelId") as string | undefined
const actModeThinkingBudgetTokens = context.globalState.get("actModeThinkingBudgetTokens") as number | undefined
const actModeReasoningEffort = context.globalState.get("actModeReasoningEffort") as string | undefined
const actModeVsCodeLmModelSelector = context.globalState.get("actModeVsCodeLmModelSelector") as
| LanguageModelChatSelector
| undefined
const actModeAwsBedrockCustomSelected = context.globalState.get("actModeAwsBedrockCustomSelected") as boolean | undefined
const actModeAwsBedrockCustomModelBaseId = context.globalState.get("actModeAwsBedrockCustomModelBaseId") as
| BedrockModelId
| undefined
const actModeOpenRouterModelId = context.globalState.get("actModeOpenRouterModelId") as string | undefined
const actModeOpenRouterModelInfo = context.globalState.get("actModeOpenRouterModelInfo") as ModelInfo | undefined
const actModeOpenAiModelId = context.globalState.get("actModeOpenAiModelId") as string | undefined
const actModeOpenAiModelInfo = context.globalState.get("actModeOpenAiModelInfo") as ModelInfo | undefined
const actModeOllamaModelId = context.globalState.get("actModeOllamaModelId") as string | undefined
const actModeLmStudioModelId = context.globalState.get("actModeLmStudioModelId") as string | undefined
const actModeLiteLlmModelId = context.globalState.get("actModeLiteLlmModelId") as string | undefined
const actModeLiteLlmModelInfo = context.globalState.get("actModeLiteLlmModelInfo") as ModelInfo | undefined
const actModeRequestyModelId = context.globalState.get("actModeRequestyModelId") as string | undefined
const actModeRequestyModelInfo = context.globalState.get("actModeRequestyModelInfo") as ModelInfo | undefined
const actModeTogetherModelId = context.globalState.get("actModeTogetherModelId") as string | undefined
const actModeFireworksModelId = context.globalState.get("actModeFireworksModelId") as string | undefined
const actModeSapAiCoreModelId = context.globalState.get("actModeSapAiCoreModelId") as string | undefined
const actModeGroqModelId = context.globalState.get("actModeGroqModelId") as string | undefined
const actModeGroqModelInfo = context.globalState.get("actModeGroqModelInfo") as ModelInfo | undefined
const actModeHuggingFaceModelId = context.globalState.get("actModeHuggingFaceModelId") as string | undefined
const actModeHuggingFaceModelInfo = context.globalState.get("actModeHuggingFaceModelInfo") as ModelInfo | undefined
const actModeHuaweiCloudMaasModelId = context.globalState.get("actModeHuaweiCloudMaasModelId") as string | undefined
const actModeHuaweiCloudMaasModelInfo = context.globalState.get("actModeHuaweiCloudMaasModelInfo") as
| ModelInfo
| undefined
const actModeBasetenModelId = context.globalState.get("actModeBasetenModelId") as string | undefined
const actModeBasetenModelInfo = context.globalState.get("actModeBasetenModelInfo") as ModelInfo | undefined
const actModeVercelAiGatewayModelId = context.globalState.get("actModeVercelAiGatewayModelId") as string | undefined
const actModeVercelAiGatewayModelInfo = context.globalState.get("actModeVercelAiGatewayModelInfo") as
| ModelInfo
| undefined
const sapAiCoreUseOrchestrationMode = context.globalState.get("sapAiCoreUseOrchestrationMode") as boolean | undefined
// Other global fields
focusChainSettings: focusChainSettings || DEFAULT_FOCUS_CHAIN_SETTINGS,
focusChainFeatureFlagEnabled: focusChainFeatureFlagEnabled ?? false,
strictPlanModeEnabled: strictPlanModeEnabled ?? true,
useAutoCondense: useAutoCondense ?? true,
isNewUser: isNewUser ?? true,
welcomeViewCompleted,
lastShownAnnouncementId,
taskHistory: taskHistory || [],
autoApprovalSettings: autoApprovalSettings || DEFAULT_AUTO_APPROVAL_SETTINGS, // default value can be 0 or empty string
globalClineRulesToggles: globalClineRulesToggles || {},
browserSettings: { ...DEFAULT_BROWSER_SETTINGS, ...browserSettings }, // this will ensure that older versions of browserSettings (e.g. before remoteBrowserEnabled was added) are merged with the default values (false for remoteBrowserEnabled)
preferredLanguage: preferredLanguage || "English",
openaiReasoningEffort: (openaiReasoningEffort as OpenaiReasoningEffort) || "medium",
mode: mode || "act",
userInfo,
mcpMarketplaceEnabled: mcpMarketplaceEnabledRaw ?? true,
mcpDisplayMode: mcpDisplayMode ?? DEFAULT_MCP_DISPLAY_MODE,
mcpResponsesCollapsed: mcpResponsesCollapsed,
telemetrySetting: telemetrySetting || "unset",
planActSeparateModelsSetting,
enableCheckpointsSetting: enableCheckpointsSettingRaw ?? true,
shellIntegrationTimeout: shellIntegrationTimeout || 4000,
terminalReuseEnabled: terminalReuseEnabled ?? true,
terminalOutputLineLimit: terminalOutputLineLimit ?? 500,
defaultTerminalProfile: defaultTerminalProfile ?? "default",
globalWorkflowToggles: globalWorkflowToggles || {},
mcpMarketplaceCatalog,
qwenCodeOauthPath,
customPrompt,
let apiProvider: ApiProvider
if (planModeApiProvider) {
apiProvider = planModeApiProvider
} else {
// New users should default to openrouter, since they've opted to use an API key instead of signing in
apiProvider = "openrouter"
}
const mcpResponsesCollapsed = mcpResponsesCollapsedRaw ?? false
// Plan/Act separate models setting is a boolean indicating whether the user wants to use different models for plan and act. Existing users expect this to be enabled, while we want new users to opt in to this being disabled by default.
// On win11 state sometimes initializes as empty string instead of undefined
let planActSeparateModelsSetting: boolean | undefined
if (planActSeparateModelsSettingRaw === true || planActSeparateModelsSettingRaw === false) {
planActSeparateModelsSetting = planActSeparateModelsSettingRaw
} else {
// default to true for existing users
if (planModeApiProvider) {
planActSeparateModelsSetting = true
} else {
// default to false for new users
planActSeparateModelsSetting = false
}
}
const taskHistory = await readTaskHistoryFromState(context)
return {
// api configuration fields
claudeCodePath,
awsRegion,
awsUseCrossRegionInference,
awsBedrockUsePromptCache,
awsBedrockEndpoint,
awsProfile,
awsUseProfile,
awsAuthentication,
vertexProjectId,
vertexRegion,
openAiBaseUrl,
requestyBaseUrl,
openAiHeaders: openAiHeaders || {},
ollamaBaseUrl,
ollamaApiOptionsCtxNum,
lmStudioBaseUrl,
lmStudioMaxTokens,
anthropicBaseUrl,
geminiBaseUrl,
qwenApiLine,
moonshotApiLine,
zaiApiLine,
azureApiVersion,
openRouterProviderSorting,
liteLlmBaseUrl,
liteLlmUsePromptCache,
fireworksModelMaxCompletionTokens,
fireworksModelMaxTokens,
asksageApiUrl,
favoritedModelIds,
requestTimeoutMs,
sapAiCoreBaseUrl,
sapAiCoreTokenUrl,
sapAiResourceGroup,
difyBaseUrl,
sapAiCoreUseOrchestrationMode,
// Plan mode configurations
planModeApiProvider: planModeApiProvider || apiProvider,
planModeApiModelId,
planModeThinkingBudgetTokens,
planModeReasoningEffort,
planModeVsCodeLmModelSelector,
planModeAwsBedrockCustomSelected,
planModeAwsBedrockCustomModelBaseId,
planModeOpenRouterModelId,
planModeOpenRouterModelInfo,
planModeOpenAiModelId,
planModeOpenAiModelInfo,
planModeOllamaModelId,
planModeLmStudioModelId,
planModeLiteLlmModelId,
planModeLiteLlmModelInfo,
planModeRequestyModelId,
planModeRequestyModelInfo,
planModeTogetherModelId,
planModeFireworksModelId,
planModeSapAiCoreModelId,
planModeGroqModelId,
planModeGroqModelInfo,
planModeHuggingFaceModelId,
planModeHuggingFaceModelInfo,
planModeHuaweiCloudMaasModelId,
planModeHuaweiCloudMaasModelInfo,
planModeBasetenModelId,
planModeBasetenModelInfo,
planModeVercelAiGatewayModelId,
planModeVercelAiGatewayModelInfo,
// Act mode configurations
actModeApiProvider: actModeApiProvider || apiProvider,
actModeApiModelId,
actModeThinkingBudgetTokens,
actModeReasoningEffort,
actModeVsCodeLmModelSelector,
actModeAwsBedrockCustomSelected,
actModeAwsBedrockCustomModelBaseId,
actModeOpenRouterModelId,
actModeOpenRouterModelInfo,
actModeOpenAiModelId,
actModeOpenAiModelInfo,
actModeOllamaModelId,
actModeLmStudioModelId,
actModeLiteLlmModelId,
actModeLiteLlmModelInfo,
actModeRequestyModelId,
actModeRequestyModelInfo,
actModeTogetherModelId,
actModeFireworksModelId,
actModeSapAiCoreModelId,
actModeGroqModelId,
actModeGroqModelInfo,
actModeHuggingFaceModelId,
actModeHuggingFaceModelInfo,
actModeHuaweiCloudMaasModelId,
actModeHuaweiCloudMaasModelInfo,
actModeBasetenModelId,
actModeBasetenModelInfo,
actModeVercelAiGatewayModelId,
actModeVercelAiGatewayModelInfo,
// Other global fields
focusChainSettings: focusChainSettings || DEFAULT_FOCUS_CHAIN_SETTINGS,
focusChainFeatureFlagEnabled: focusChainFeatureFlagEnabled ?? false,
strictPlanModeEnabled: strictPlanModeEnabled ?? true,
useAutoCondense: useAutoCondense ?? false,
isNewUser: isNewUser ?? true,
welcomeViewCompleted,
lastShownAnnouncementId,
taskHistory: taskHistory || [],
autoApprovalSettings: autoApprovalSettings || DEFAULT_AUTO_APPROVAL_SETTINGS, // default value can be 0 or empty string
globalClineRulesToggles: globalClineRulesToggles || {},
browserSettings: { ...DEFAULT_BROWSER_SETTINGS, ...browserSettings }, // this will ensure that older versions of browserSettings (e.g. before remoteBrowserEnabled was added) are merged with the default values (false for remoteBrowserEnabled)
preferredLanguage: preferredLanguage || "English",
openaiReasoningEffort: (openaiReasoningEffort as OpenaiReasoningEffort) || "medium",
mode: mode || "act",
userInfo,
mcpMarketplaceEnabled: mcpMarketplaceEnabledRaw ?? true,
mcpDisplayMode: mcpDisplayMode ?? DEFAULT_MCP_DISPLAY_MODE,
mcpResponsesCollapsed: mcpResponsesCollapsed,
telemetrySetting: telemetrySetting || "unset",
planActSeparateModelsSetting,
enableCheckpointsSetting: enableCheckpointsSettingRaw ?? true,
shellIntegrationTimeout: shellIntegrationTimeout || 4000,
terminalReuseEnabled: terminalReuseEnabled ?? true,
terminalOutputLineLimit: terminalOutputLineLimit ?? 500,
defaultTerminalProfile: defaultTerminalProfile ?? "default",
globalWorkflowToggles: globalWorkflowToggles || {},
mcpMarketplaceCatalog,
qwenCodeOauthPath,
customPrompt,
}
} catch (error) {
console.error("[StateHelpers] Failed to read global state:", error)
throw error
}
}
+22 -3
View File
@@ -12,6 +12,7 @@ import { FocusChainSettings } from "@shared/FocusChainSettings"
import { Mode } from "@shared/storage/types"
import { ClineAskResponse } from "@shared/WebviewMessage"
import * as vscode from "vscode"
import { modelDoesntSupportWebp } from "@/utils/model-utils"
import { ToolUse, ToolUseName } from "../assistant-message"
import { ContextManager } from "../context/context-management/ContextManager"
import { formatResponse } from "../prompts/responses"
@@ -119,6 +120,7 @@ export class ToolExecutor {
}
// Create a properly typed TaskConfig object for handlers
// NOTE: modifying this object in the tool handlers is okay since these are all references to the singular ToolExecutor instance's variables. However, be careful modifying this object assuming it will update the ToolExecutor instance, e.g. config.browserSession = ... will not update the ToolExecutor.browserSession instance variable. Use applyLatestBrowserSettings() instead.
private asToolConfig(): TaskConfig {
const config: TaskConfig = {
taskId: this.taskId,
@@ -157,7 +159,9 @@ export class ToolExecutor {
updateFCListFromToolResponse: this.updateFCListFromToolResponse,
sayAndCreateMissingParamError: this.sayAndCreateMissingParamError,
removeLastPartialMessageIfExistsWithType: this.removeLastPartialMessageIfExistsWithType,
shouldAutoApproveTool: this.shouldAutoApproveTool.bind(this),
shouldAutoApproveToolWithPath: this.shouldAutoApproveToolWithPath.bind(this),
applyLatestBrowserSettings: this.applyLatestBrowserSettings.bind(this),
},
coordinator: this.coordinator,
}
@@ -222,6 +226,22 @@ export class ToolExecutor {
await this.execute(block)
}
/**
* Updates the browser settings
*/
public async applyLatestBrowserSettings() {
if (this.context) {
await this.browserSession.dispose()
const apiHandlerModel = this.api.getModel()
const useWebp = this.api ? !modelDoesntSupportWebp(apiHandlerModel) : true
this.browserSession = new BrowserSession(this.context, this.browserSettings, useWebp)
} else {
console.warn("no controller context available for browserSession")
}
return this.browserSession
}
/**
* Handles errors during tool execution
*/
@@ -305,6 +325,7 @@ export class ToolExecutor {
// Handle complete blocks
await this.handleCompleteBlock(block, config)
await this.saveCheckpoint()
return true
} catch (error) {
await this.handleError(`executing ${block.name}`, error as Error, block)
@@ -351,15 +372,13 @@ export class ToolExecutor {
* Handle complete block execution
*/
private async handleCompleteBlock(block: ToolUse, config: any): Promise<void> {
// All tools are now fully self-managed and implement IPartialBlockHandler
const result = await this.coordinator.execute(config, block)
this.pushToolResult(result, block)
// Handle focus chain updates
if (!block.partial && this.focusChainSettings.enabled) {
await this.updateFCListFromToolResponse(block.params.task_progress)
}
await this.saveCheckpoint()
}
}
+2 -1
View File
@@ -1,7 +1,8 @@
import { featureFlagsService, telemetryService } from "@services/posthog/PostHogClientProvider"
import { FocusChainSettings } from "@shared/FocusChainSettings"
import * as fs from "fs/promises"
import * as vscode from "vscode"
import { featureFlagsService } from "@/services/feature-flags"
import { telemetryService } from "@/services/telemetry"
import { HostProvider } from "../../../hosts/host-provider"
import { ClineSay } from "../../../shared/ExtensionMessage"
import { FileChangeEvent_ChangeType, SubscribeToFileRequest } from "../../../shared/proto/host/watch"
+2 -2
View File
@@ -43,7 +43,6 @@ import { UrlContentFetcher } from "@services/browser/UrlContentFetcher"
import { listFiles } from "@services/glob/list-files"
import { Logger } from "@services/logging/Logger"
import { McpHub } from "@services/mcp/McpHub"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { AutoApprovalSettings } from "@shared/AutoApprovalSettings"
import { ApiConfiguration } from "@shared/api"
import { findLast, findLastIndex } from "@shared/array"
@@ -70,7 +69,8 @@ import * as vscode from "vscode"
import type { SystemPromptContext } from "@/core/prompts/system-prompt"
import { getSystemPrompt } from "@/core/prompts/system-prompt"
import { HostProvider } from "@/hosts/host-provider"
import { errorService } from "@/services/posthog/PostHogClientProvider"
import { errorService } from "@/services/error"
import { telemetryService } from "@/services/telemetry"
import { ShowMessageType } from "@/shared/proto/index.host"
import { isInTestMode } from "../../services/test/TestMode"
import { ensureLocalClineDirExists } from "../context/instructions/user-instructions/rule-helpers"
@@ -1,12 +1,13 @@
import type { ToolUse } from "@core/assistant-message"
import { formatResponse } from "@core/prompts/responses"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { ClineAsk } from "@shared/ExtensionMessage"
import { ClineAsk, ClineAskUseMcpServer } from "@shared/ExtensionMessage"
import { telemetryService } from "@/services/telemetry"
import type { ToolResponse } from "../../index"
import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils"
import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
export class AccessMcpResourceHandler implements IFullyManagedTool {
readonly name = "access_mcp_resource"
@@ -21,21 +22,16 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
const server_name = block.params.server_name
const uri = block.params.uri
// Early return if we don't have enough data yet
if (!server_name || !uri) {
return
}
const partialMessage = JSON.stringify({
type: "access_mcp_resource",
serverName: uiHelpers.removeClosingTag(block, "server_name", server_name),
toolName: undefined,
uri: uiHelpers.removeClosingTag(block, "uri", uri),
arguments: undefined,
})
} satisfies ClineAskUseMcpServer)
// Check if tool should be auto-approved (access_mcp_resource uses general auto-approval)
const shouldAutoApprove = uiHelpers.shouldAutoApproveTool("access_mcp_resource")
const shouldAutoApprove = uiHelpers.shouldAutoApproveTool(block.name)
if (shouldAutoApprove) {
await uiHelpers.removeLastPartialMessageIfExistsWithType("ask", "use_mcp_server")
@@ -47,11 +43,6 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, return empty string to let coordinator handle UI
if (block.partial) {
return ""
}
const server_name: string | undefined = block.params.server_name
const uri: string | undefined = block.params.uri
@@ -75,10 +66,9 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
toolName: undefined,
uri: uri,
arguments: undefined,
})
} satisfies ClineAskUseMcpServer)
// access_mcp_resource uses general auto-approval
const shouldAutoApprove = config.autoApprovalSettings.actions.useMcp
const shouldAutoApprove = config.callbacks.shouldAutoApproveTool(block.name)
if (shouldAutoApprove) {
// Auto-approval flow
@@ -101,45 +91,36 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "use_mcp_server")
// Ask for approval
const { response } = await config.callbacks.ask("use_mcp_server", completeMessage, false)
if (response !== "yesButtonClicked") {
// Handle rejection
config.taskState.didRejectTool = true
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("use_mcp_server", completeMessage, config)
if (!didApprove) {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, false)
return "The user denied this operation."
return formatResponse.toolDenied()
} else {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, true)
}
}
// Show MCP request started message
await config.callbacks.say("mcp_server_request_started")
try {
// Execute the MCP resource access
const resourceResult = await config.services.mcpHub.readResource(server_name, uri)
// Execute the MCP resource access
const resourceResult = await config.services.mcpHub.readResource(server_name, uri)
// Process the resource result
const resourceResultPretty =
resourceResult?.contents
.map((item: any) => {
if (item.text) {
return item.text
}
return ""
})
.filter(Boolean)
.join("\n\n") || "(Empty response)"
// Process the resource result
const resourceResultPretty =
resourceResult?.contents
.map((item: any) => {
if (item.text) {
return item.text
}
return ""
})
.filter(Boolean)
.join("\n\n") || "(Empty response)"
// Display result to user
await config.callbacks.say("mcp_server_response", resourceResultPretty)
// Display result to user
await config.callbacks.say("mcp_server_response", resourceResultPretty)
// Return formatted result
return formatResponse.toolResult(resourceResultPretty)
} catch (error) {
return `Error accessing MCP resource: ${(error as Error)?.message}`
}
// Return formatted result
return formatResponse.toolResult(resourceResultPretty)
}
}
@@ -1,8 +1,8 @@
import { processFilesIntoText } from "@integrations/misc/extract-text"
import { showSystemNotification } from "@integrations/notifications"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { findLast, parsePartialArrayString } from "@shared/array"
import { ClineAsk, ClineAskQuestion } from "@shared/ExtensionMessage"
import { telemetryService } from "@/services/telemetry"
import { ToolUse, ToolUseName } from "../../../assistant-message"
import { formatResponse } from "../../../prompts/responses"
import { ToolResponse } from "../.."
@@ -26,79 +26,68 @@ export class AskFollowupQuestionToolHandler implements IToolHandler, IPartialBlo
options: parsePartialArrayString(uiHelpers.removeClosingTag(block, "options", optionsRaw)),
} satisfies ClineAskQuestion
// For followup, just stream ask messages
await uiHelpers.removeLastPartialMessageIfExistsWithType("say", "followup")
await uiHelpers.ask("followup" as ClineAsk, JSON.stringify(sharedMessage), block.partial).catch(() => {})
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, don't execute yet
if (block.partial) {
return ""
const question: string | undefined = block.params.question
const optionsRaw: string | undefined = block.params.options
// Validate required parameter
if (!question) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError("ask_followup_question", "question")
}
config.taskState.consecutiveMistakeCount = 0
// Show notification if auto-approval is enabled
if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) {
showSystemNotification({
subtitle: "Cline has a question...",
message: question.replace(/\n/g, " "),
})
}
try {
const question: string | undefined = block.params.question
const optionsRaw: string | undefined = block.params.options
const sharedMessage = {
question: question,
options: parsePartialArrayString(optionsRaw || "[]"),
} satisfies ClineAskQuestion
// Validate required parameter
if (!question) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError("ask_followup_question", "question")
const options = parsePartialArrayString(optionsRaw || "[]")
// Ask the question
const {
text,
images,
files: followupFiles,
} = await config.callbacks.ask("followup", JSON.stringify(sharedMessage), false)
// Check if options contains the text response
if (optionsRaw && text && options.includes(text)) {
telemetryService.captureOptionSelected(config.ulid, options.length, "act")
// Valid option selected, update last followup message with selected option
const clineMessages = config.messageState.getClineMessages()
const lastFollowupMessage = findLast(clineMessages, (m: any) => m.ask === "followup")
if (lastFollowupMessage) {
lastFollowupMessage.text = JSON.stringify({
...sharedMessage,
selected: text,
} satisfies ClineAskQuestion)
await config.messageState.saveClineMessagesAndUpdateHistory()
}
config.taskState.consecutiveMistakeCount = 0
// Show notification if auto-approval is enabled
if (config.autoApprovalSettings.enabled && config.autoApprovalSettings.enableNotifications) {
showSystemNotification({
subtitle: "Cline has a question...",
message: question.replace(/\n/g, " "),
})
}
const sharedMessage = {
question: question,
options: parsePartialArrayString(optionsRaw || "[]"),
} satisfies ClineAskQuestion
const options = parsePartialArrayString(optionsRaw || "[]")
// Ask the question
const {
text,
images,
files: followupFiles,
} = await config.callbacks.ask("followup", JSON.stringify(sharedMessage), false)
// Check if options contains the text response
if (optionsRaw && text && options.includes(text)) {
telemetryService.captureOptionSelected(config.ulid, options.length, "act")
// Valid option selected, update last followup message with selected option
const clineMessages = config.messageState.getClineMessages()
const lastFollowupMessage = findLast(clineMessages, (m: any) => m.ask === "followup")
if (lastFollowupMessage) {
lastFollowupMessage.text = JSON.stringify({
...sharedMessage,
selected: text,
} satisfies ClineAskQuestion)
await config.messageState.saveClineMessagesAndUpdateHistory()
}
} else {
// Option not selected, send user feedback
telemetryService.captureOptionsIgnored(config.ulid, options.length, "act")
await config.callbacks.say("user_feedback", text ?? "", images, followupFiles)
}
// Process any attached files
let fileContentString = ""
if (followupFiles && followupFiles.length > 0) {
fileContentString = await processFilesIntoText(followupFiles)
}
return formatResponse.toolResult(`<answer>\n${text}\n</answer>`, images, fileContentString)
} catch (error) {
return `Error asking question: ${(error as Error).message}`
} else {
// Option not selected, send user feedback
telemetryService.captureOptionsIgnored(config.ulid, options.length, "act")
await config.callbacks.say("user_feedback", text ?? "", images, followupFiles)
}
// Process any attached files
let fileContentString = ""
if (followupFiles && followupFiles.length > 0) {
fileContentString = await processFilesIntoText(followupFiles)
}
return formatResponse.toolResult(`<answer>\n${text}\n</answer>`, images, fileContentString)
}
}
@@ -3,13 +3,14 @@ import type { ToolUse } from "@core/assistant-message"
import { formatResponse } from "@core/prompts/responses"
import { processFilesIntoText } from "@integrations/misc/extract-text"
import { showSystemNotification } from "@integrations/notifications"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { findLastIndex } from "@shared/array"
import { COMPLETION_RESULT_CHANGES_FLAG } from "@shared/ExtensionMessage"
import { telemetryService } from "@/services/telemetry"
import type { ToolResponse } from "../../index"
import type { IPartialBlockHandler, IToolHandler } from "../ToolExecutorCoordinator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
export class AttemptCompletionHandler implements IToolHandler, IPartialBlockHandler {
readonly name = "attempt_completion"
@@ -28,37 +29,26 @@ export class AttemptCompletionHandler implements IToolHandler, IPartialBlockHand
const result = block.params.result
const command = block.params.command
if (command) {
// the attempt_completion text is done, now we're getting command
// Original had complex logic here but most was commented out
// For now, we'll keep it simple and not stream command (matching original's disabled approach)
// But we can still stream result if we have it
if (result) {
const cleanResult = uiHelpers.removeClosingTag(block, "result", result)
await uiHelpers.say("completion_result", cleanResult, undefined, undefined, true)
}
} else {
// no command, still outputting partial result - MATCH ORIGINAL EXACTLY
if (result) {
const cleanResult = uiHelpers.removeClosingTag(block, "result", result)
await uiHelpers.say("completion_result", cleanResult, undefined, undefined, true)
}
if (!command) {
// no command, still outputting partial result
await uiHelpers.say(
"completion_result",
uiHelpers.removeClosingTag(block, "result", result),
undefined,
undefined,
block.partial,
)
}
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, don't execute yet
if (block.partial) {
return ""
}
const result: string | undefined = block.params.result
const command: string | undefined = block.params.command
// Validate required parameters
if (!result) {
config.taskState.consecutiveMistakeCount++
return "Missing required parameter: result"
return await config.callbacks.sayAndCreateMissingParamError("attempt_completion", "result")
}
config.taskState.consecutiveMistakeCount = 0
@@ -107,10 +97,9 @@ export class AttemptCompletionHandler implements IToolHandler, IPartialBlockHand
}
// complete command message - need to ask for approval
const { response } = await config.callbacks.ask("command", command, false)
if (response !== "yesButtonClicked") {
// User rejected the command
return "The user denied the command execution."
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("command", command, config)
if (!didApprove) {
return formatResponse.toolDenied()
}
// User approved, execute the command
@@ -129,13 +118,16 @@ export class AttemptCompletionHandler implements IToolHandler, IPartialBlockHand
}
// we already sent completion_result says, an empty string asks relinquishes control over button and field
// in case last command was interactive and in partial state, the UI is expecting an ask response. This ends the command ask response, freeing up the UI to proceed with the completion ask.
if (config.messageState.getClineMessages().at(-1)?.ask === "command_output") {
await config.callbacks.say("command_output", "")
}
const { response, text, images, files: completionFiles } = await config.callbacks.ask("completion_result", "", false)
if (response === "yesButtonClicked") {
return "" // signals to recursive loop to stop (for now this never happens since yesButtonClicked will trigger a new task)
}
await config.callbacks.say("user_feedback", text ?? "", images, completionFiles)
await config.callbacks.saveCheckpoint()
const toolResults: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] = []
if (commandResult) {
@@ -1,12 +1,12 @@
import { BrowserSession } from "@services/browser/BrowserSession"
import { BrowserAction, BrowserActionResult, browserActions, ClineSayBrowserAction } from "@shared/ExtensionMessage"
import { modelDoesntSupportWebp } from "@utils/model-utils"
import { ToolUse } from "../../../assistant-message"
import { formatResponse } from "../../../prompts/responses"
import { ToolResponse } from "../.."
import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils"
import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
export class BrowserToolHandler implements IFullyManagedTool {
readonly name = "browser_action"
@@ -59,11 +59,6 @@ export class BrowserToolHandler implements IFullyManagedTool {
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, don't execute yet
if (block.partial) {
return ""
}
const action: BrowserAction | undefined = block.params.action as BrowserAction
const url: string | undefined = block.params.url
const coordinate: string | undefined = block.params.coordinate
@@ -75,7 +70,6 @@ export class BrowserToolHandler implements IFullyManagedTool {
config.taskState.consecutiveMistakeCount++
const errorResult = await config.callbacks.sayAndCreateMissingParamError("browser_action", "action")
await config.services.browserSession.closeBrowser()
await config.callbacks.saveCheckpoint()
return errorResult
}
@@ -88,7 +82,6 @@ export class BrowserToolHandler implements IFullyManagedTool {
config.taskState.consecutiveMistakeCount++
const errorResult = await config.callbacks.sayAndCreateMissingParamError("browser_action", "url")
await config.services.browserSession.closeBrowser()
await config.callbacks.saveCheckpoint()
return errorResult
}
config.taskState.consecutiveMistakeCount = 0
@@ -96,21 +89,20 @@ export class BrowserToolHandler implements IFullyManagedTool {
// Handle approval flow for launch using callbacks
const autoApprover = config.autoApprover || { shouldAutoApproveTool: () => false }
if (autoApprover.shouldAutoApproveTool(block.name)) {
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "browser_action_launch")
await config.callbacks.say("browser_action_launch", url, undefined, undefined, false)
config.taskState.consecutiveAutoApprovedRequestsCount++
} else {
// Show notification for approval if auto approval enabled
const { showNotificationForApprovalIfAutoApprovalEnabled } = require("../../utils")
showNotificationForApprovalIfAutoApprovalEnabled(
`Cline wants to use a browser and launch ${url}`,
config.autoApprovalSettings.enabled,
config.autoApprovalSettings.enableNotifications,
)
const { response } = await config.callbacks.ask("browser_action_launch", url, false)
if (response !== "yesButtonClicked") {
await config.callbacks.saveCheckpoint()
return formatResponse.toolResult("The user rejected this browser action.")
await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "browser_action_launch")
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("browser_action_launch", url, config)
if (!didApprove) {
return formatResponse.toolDenied()
}
}
@@ -118,15 +110,8 @@ export class BrowserToolHandler implements IFullyManagedTool {
await config.callbacks.say("browser_action_result", "")
// Re-make browserSession to make sure latest settings apply
const browserSession = config.services.browserSession
if (config.context) {
await browserSession.dispose()
const apiHandlerModel = config.api.getModel()
const useWebp = config.api ? !modelDoesntSupportWebp(apiHandlerModel) : true
config.services.browserSession = new BrowserSession(config.context, config.browserSettings, useWebp)
} else {
console.warn("no controller context available for browserSession")
}
// This updates the ToolExecutor browserSession and returns it, for us to modify the local config object accordingly. (Previously we would set config.services.browserSession = new BrowserSession... but this would not update the ToolExecutor.browserSession which is used in subsequent browser tool calls)
config.services.browserSession = await config.callbacks.applyLatestBrowserSettings()
await config.services.browserSession.launchBrowser()
browserActionResult = await config.services.browserSession.navigateToUrl(url)
} else {
@@ -136,7 +121,6 @@ export class BrowserToolHandler implements IFullyManagedTool {
config.taskState.consecutiveMistakeCount++
const errorResult = await config.callbacks.sayAndCreateMissingParamError("browser_action", "coordinate")
await config.services.browserSession.closeBrowser()
await config.callbacks.saveCheckpoint()
return errorResult
}
}
@@ -145,7 +129,6 @@ export class BrowserToolHandler implements IFullyManagedTool {
config.taskState.consecutiveMistakeCount++
const errorResult = await config.callbacks.sayAndCreateMissingParamError("browser_action", "text")
await config.services.browserSession.closeBrowser()
await config.callbacks.saveCheckpoint()
return errorResult
}
}
@@ -200,22 +183,17 @@ export class BrowserToolHandler implements IFullyManagedTool {
browserActionResult.screenshot ? [browserActionResult.screenshot] : [],
)
await config.callbacks.saveCheckpoint()
return result
case "close":
const closeResult = formatResponse.toolResult(
`The browser has been closed. You may now proceed to using other tools.`,
)
await config.callbacks.saveCheckpoint()
return closeResult
}
} catch (error) {
await config.services.browserSession.closeBrowser() // if any error occurs, the browser session is terminated
return `Error executing browser action: ${(error as Error).message}`
throw error
}
// This should never be reached, but TypeScript requires a return
return ""
}
}
@@ -19,11 +19,6 @@ export class CondenseHandler implements IToolHandler, IPartialBlockHandler {
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, don't execute yet
if (block.partial) {
return ""
}
const context: string | undefined = block.params.context
// Validate required parameters
@@ -1,16 +1,17 @@
import type { ToolUse } from "@core/assistant-message"
import { formatResponse } from "@core/prompts/responses"
import { showSystemNotification } from "@integrations/notifications"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { COMMAND_REQ_APP_STRING } from "@shared/combineCommandSequences"
import { ClineAsk } from "@shared/ExtensionMessage"
import { fixModelHtmlEscaping } from "@utils/string"
import { telemetryService } from "@/services/telemetry"
import type { ToolResponse } from "../../index"
import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils"
import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
export class ExecuteCommandToolHandler implements IFullyManagedTool {
readonly name = "execute_command"
@@ -24,15 +25,6 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const command = block.params.command
// For commands, we need to wait for the requires_approval parameter before showing UI
// This is because the approval flow depends on that parameter
if (!block.params.requires_approval) {
return // Wait for complete block
}
// Command partial streaming is handled differently - just show the command
const partialCommand = uiHelpers.removeClosingTag(block, "command", command)
// Check if this should be auto-approved to determine UI flow
const shouldAutoApprove = uiHelpers.shouldAutoApproveTool("execute_command")
@@ -42,109 +34,101 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
// So we wait for the complete block
return
} else {
// For manual approval, stream the ask message
await uiHelpers.removeLastPartialMessageIfExistsWithType("say", "command")
await uiHelpers.ask("command" as ClineAsk, partialCommand, block.partial).catch(() => {})
await uiHelpers
.ask("command" as ClineAsk, uiHelpers.removeClosingTag(block, "command", command), block.partial)
.catch(() => {})
}
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, don't execute yet
if (block.partial) {
return ""
let command: string | undefined = block.params.command
const requiresApprovalRaw: string | undefined = block.params.requires_approval
const requiresApprovalPerLLM = requiresApprovalRaw?.toLowerCase() === "true"
// Validate required parameters
if (!command) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError("execute_command", "command")
}
try {
let command: string | undefined = block.params.command
const requiresApprovalRaw: string | undefined = block.params.requires_approval
const requiresApprovalPerLLM = requiresApprovalRaw?.toLowerCase() === "true"
// Validate required parameters
if (!command) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError("execute_command", "command")
}
if (!requiresApprovalRaw) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError("execute_command", "requires_approval")
}
config.taskState.consecutiveMistakeCount = 0
// Pre-process command for certain models
if (config.api.getModel().id.includes("gemini")) {
command = fixModelHtmlEscaping(command)
}
// Check clineignore validation for command
const ignoredFileAttemptedToAccess = config.services.clineIgnoreController.validateCommand(command)
if (ignoredFileAttemptedToAccess) {
await config.callbacks.say("clineignore_error", ignoredFileAttemptedToAccess)
return formatResponse.toolError(formatResponse.clineIgnoreError(ignoredFileAttemptedToAccess))
}
let didAutoApprove = false
// Complex dual approval system for commands
const autoApproveResult = config.autoApprover?.shouldAutoApproveTool(block.name)
const [autoApproveSafe, autoApproveAll] = Array.isArray(autoApproveResult)
? autoApproveResult
: [autoApproveResult, false]
if ((!requiresApprovalPerLLM && autoApproveSafe) || (requiresApprovalPerLLM && autoApproveSafe && autoApproveAll)) {
// Auto-approve flow
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "command")
await config.callbacks.say("command", command, undefined, undefined, false)
config.taskState.consecutiveAutoApprovedRequestsCount++
didAutoApprove = true
telemetryService.captureToolUsage(config.ulid, "execute_command", config.api.getModel().id, true, true)
} else {
// Manual approval flow
showNotificationForApprovalIfAutoApprovalEnabled(
`Cline wants to execute a command: ${command}`,
config.autoApprovalSettings.enabled,
config.autoApprovalSettings.enableNotifications,
)
const { response } = await config.callbacks.ask(
"command",
command + `${autoApproveSafe && requiresApprovalPerLLM ? COMMAND_REQ_APP_STRING : ""}`,
false,
)
if (response !== "yesButtonClicked") {
telemetryService.captureToolUsage(config.ulid, "execute_command", config.api.getModel().id, false, false)
return "The user denied this operation."
}
telemetryService.captureToolUsage(config.ulid, "execute_command", config.api.getModel().id, false, true)
}
// Setup timeout notification for long-running auto-approved commands
let timeoutId: NodeJS.Timeout | undefined
if (didAutoApprove && config.autoApprovalSettings.enableNotifications) {
timeoutId = setTimeout(() => {
showSystemNotification({
subtitle: "Command is still running",
message: "An auto-approved command has been running for 30s, and may need your attention.",
})
}, 30_000)
}
// Execute the command
const [userRejected, result] = await config.callbacks.executeCommandTool(command)
if (timeoutId) {
clearTimeout(timeoutId)
}
if (userRejected) {
config.taskState.didRejectTool = true
}
return result
} catch (error) {
return `Error executing command: ${(error as Error).message}`
if (!requiresApprovalRaw) {
config.taskState.consecutiveMistakeCount++
return await config.callbacks.sayAndCreateMissingParamError("execute_command", "requires_approval")
}
config.taskState.consecutiveMistakeCount = 0
// Pre-process command for certain models
if (config.api.getModel().id.includes("gemini")) {
command = fixModelHtmlEscaping(command)
}
// Check clineignore validation for command
const ignoredFileAttemptedToAccess = config.services.clineIgnoreController.validateCommand(command)
if (ignoredFileAttemptedToAccess) {
await config.callbacks.say("clineignore_error", ignoredFileAttemptedToAccess)
return formatResponse.toolError(formatResponse.clineIgnoreError(ignoredFileAttemptedToAccess))
}
let didAutoApprove = false
// If the model says this command is safe and auto approval for safe commands is true, execute the command
// If the model says the command is risky, but *BOTH* auto approve settings are true, execute the command
const autoApproveResult = config.autoApprover?.shouldAutoApproveTool(block.name)
const [autoApproveSafe, autoApproveAll] = Array.isArray(autoApproveResult)
? autoApproveResult
: [autoApproveResult, false]
if ((!requiresApprovalPerLLM && autoApproveSafe) || (requiresApprovalPerLLM && autoApproveSafe && autoApproveAll)) {
// Auto-approve flow
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "command")
await config.callbacks.say("command", command, undefined, undefined, false)
config.taskState.consecutiveAutoApprovedRequestsCount++
didAutoApprove = true
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, true, true)
} else {
// Manual approval flow
showNotificationForApprovalIfAutoApprovalEnabled(
`Cline wants to execute a command: ${command}`,
config.autoApprovalSettings.enabled,
config.autoApprovalSettings.enableNotifications,
)
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback(
"command",
command + `${autoApproveSafe && requiresApprovalPerLLM ? COMMAND_REQ_APP_STRING : ""}`,
config,
)
if (!didApprove) {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, false)
return formatResponse.toolDenied()
}
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, true)
}
// Setup timeout notification for long-running auto-approved commands
let timeoutId: NodeJS.Timeout | undefined
if (didAutoApprove && config.autoApprovalSettings.enableNotifications) {
// if the command was auto-approved, and it's long running we need to notify the user after some time has passed without proceeding
timeoutId = setTimeout(() => {
showSystemNotification({
subtitle: "Command is still running",
message: "An auto-approved command has been running for 30s, and may need your attention.",
})
}, 30_000)
}
// Execute the command
const [userRejected, result] = await config.callbacks.executeCommandTool(command)
if (timeoutId) {
clearTimeout(timeoutId)
}
if (userRejected) {
config.taskState.didRejectTool = true
}
return result
}
}
@@ -1,14 +1,16 @@
import type { ToolUse } from "@core/assistant-message"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { parseSourceCodeForDefinitionsTopLevel } from "@services/tree-sitter"
import { getReadablePath, isLocatedInWorkspace } from "@utils/path"
import * as path from "path"
import { formatResponse } from "@/core/prompts/responses"
import { telemetryService } from "@/services/telemetry"
import type { ToolResponse } from "../../index"
import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils"
import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
readonly name = "list_code_definition_names"
@@ -22,20 +24,13 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPath = block.params.path
// Early return if we don't have enough data yet
if (!relPath) {
return
}
// Get config access for services
const config = uiHelpers.getConfig()
// Create and show partial UI message
const absolutePath = path.resolve(config.cwd, relPath)
const sharedMessageProps = {
tool: "listCodeDefinitionNames",
path: getReadablePath(config.cwd, uiHelpers.removeClosingTag(block, "path", relPath)),
content: absolutePath,
content: "",
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relPath),
}
@@ -52,11 +47,6 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, return empty string to let coordinator handle UI
if (block.partial) {
return ""
}
const relDirPath: string | undefined = block.params.path
// Validate required parameters
@@ -68,12 +58,14 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
config.taskState.consecutiveMistakeCount = 0
const absolutePath = path.resolve(config.cwd, relDirPath!)
// Execute the actual parse source code operation
const result = await parseSourceCodeForDefinitionsTopLevel(absolutePath, config.services.clineIgnoreController)
// Handle approval flow
const sharedMessageProps = {
tool: "listCodeDefinitionNames",
path: getReadablePath(config.cwd, relDirPath!),
content: absolutePath,
content: result,
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relDirPath!),
}
@@ -100,22 +92,15 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool")
// Ask for approval
const { response } = await config.callbacks.ask("tool", completeMessage, false)
if (response !== "yesButtonClicked") {
// Handle rejection
config.taskState.didRejectTool = true
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
if (!didApprove) {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, false)
return "The user denied this operation."
return formatResponse.toolDenied()
} else {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, true)
}
}
// Execute the actual parse source code operation
const result = await parseSourceCodeForDefinitionsTopLevel(absolutePath, config.services.clineIgnoreController)
return result
}
}
@@ -1,15 +1,16 @@
import type { ToolUse } from "@core/assistant-message"
import { formatResponse } from "@core/prompts/responses"
import { listFiles } from "@services/glob/list-files"
import { telemetryService } from "@services/posthog/PostHogClientProvider"
import { getReadablePath, isLocatedInWorkspace } from "@utils/path"
import * as path from "path"
import { telemetryService } from "@/services/telemetry"
import type { ToolResponse } from "../../index"
import { showNotificationForApprovalIfAutoApprovalEnabled } from "../../utils"
import type { IFullyManagedTool } from "../ToolExecutorCoordinator"
import type { ToolValidator } from "../ToolValidator"
import type { TaskConfig } from "../types/TaskConfig"
import type { StronglyTypedUIHelpers } from "../types/UIHelpers"
import { ToolResultUtils } from "../utils/ToolResultUtils"
export class ListFilesToolHandler implements IFullyManagedTool {
readonly name = "list_files"
@@ -23,22 +24,16 @@ export class ListFilesToolHandler implements IFullyManagedTool {
async handlePartialBlock(block: ToolUse, uiHelpers: StronglyTypedUIHelpers): Promise<void> {
const relPath = block.params.path
// Early return if we don't have enough data yet
if (!relPath) {
return
}
// Get config access for services
const config = uiHelpers.getConfig()
// Create and show partial UI message
const absolutePath = path.resolve(config.cwd, relPath)
const recursiveRaw = block.params.recursive
const recursive = recursiveRaw?.toLowerCase() === "true"
const sharedMessageProps = {
tool: recursive ? "listFilesRecursive" : "listFilesTopLevel",
path: getReadablePath(config.cwd, uiHelpers.removeClosingTag(block, "path", relPath)),
content: absolutePath,
content: "",
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relPath),
}
@@ -55,11 +50,6 @@ export class ListFilesToolHandler implements IFullyManagedTool {
}
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
// For partial blocks, return empty string to let coordinator handle UI
if (block.partial) {
return ""
}
const relDirPath: string | undefined = block.params.path
const recursiveRaw: string | undefined = block.params.recursive
const recursive = recursiveRaw?.toLowerCase() === "true"
@@ -74,11 +64,16 @@ export class ListFilesToolHandler implements IFullyManagedTool {
config.taskState.consecutiveMistakeCount = 0
const absolutePath = path.resolve(config.cwd, relDirPath!)
// Execute the actual list files operation
const [files, didHitLimit] = await listFiles(absolutePath, recursive, 200)
const result = formatResponse.formatFilesList(absolutePath, files, didHitLimit, config.services.clineIgnoreController)
// Handle approval flow
const sharedMessageProps = {
tool: recursive ? "listFilesRecursive" : "listFilesTopLevel",
path: getReadablePath(config.cwd, relDirPath!),
content: absolutePath,
content: result,
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relDirPath!),
}
@@ -105,24 +100,15 @@ export class ListFilesToolHandler implements IFullyManagedTool {
await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "tool")
// Ask for approval
const { response } = await config.callbacks.ask("tool", completeMessage, false)
if (response !== "yesButtonClicked") {
// Handle rejection
config.taskState.didRejectTool = true
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
if (!didApprove) {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, false)
return "The user denied this operation."
return formatResponse.toolDenied()
} else {
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, false, true)
}
}
// Execute the actual list files operation
const [files, didHitLimit] = await listFiles(absolutePath, recursive, 200)
const result = formatResponse.formatFilesList(absolutePath, files, didHitLimit, config.services.clineIgnoreController)
return result
}
}

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