mirror of
https://github.com/cline/cline.git
synced 2026-09-01 23:19:18 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 54cd8e54aa | |||
| b7bb97643b | |||
| 9443ae1a35 |
@@ -13,7 +13,7 @@ service StateService {
|
||||
rpc subscribeToState(EmptyRequest) returns (stream State);
|
||||
rpc toggleFavoriteModel(StringRequest) returns (Empty);
|
||||
rpc resetState(ResetStateRequest) returns (Empty);
|
||||
rpc togglePlanActMode(TogglePlanActModeRequest) returns (Boolean);
|
||||
rpc togglePlanActModeProto(TogglePlanActModeRequest) returns (Boolean);
|
||||
rpc updateAutoApprovalSettings(AutoApprovalSettingsRequest) returns (Empty);
|
||||
rpc updateSettings(UpdateSettingsRequest) returns (Empty);
|
||||
rpc updateTelemetrySetting(TelemetrySettingRequest) returns (Empty);
|
||||
@@ -43,7 +43,7 @@ message TerminalProfileUpdateResponse {
|
||||
|
||||
message TogglePlanActModeRequest {
|
||||
Metadata metadata = 1;
|
||||
ChatSettings chat_settings = 2;
|
||||
PlanActMode mode = 2;
|
||||
optional ChatContent chat_content = 3;
|
||||
}
|
||||
|
||||
@@ -52,12 +52,6 @@ enum PlanActMode {
|
||||
ACT = 1;
|
||||
}
|
||||
|
||||
message ChatSettings {
|
||||
PlanActMode mode = 1;
|
||||
optional string preferred_language = 2;
|
||||
optional string open_ai_reasoning_effort = 3;
|
||||
}
|
||||
|
||||
message ChatContent {
|
||||
optional string message = 1;
|
||||
repeated string images = 2;
|
||||
@@ -108,12 +102,14 @@ message UpdateSettingsRequest {
|
||||
optional bool plan_act_separate_models_setting = 4;
|
||||
optional bool enable_checkpoints_setting = 5;
|
||||
optional bool mcp_marketplace_enabled = 6;
|
||||
optional ChatSettings chat_settings = 7;
|
||||
optional int32 shell_integration_timeout = 8;
|
||||
optional bool terminal_reuse_enabled = 9;
|
||||
optional bool mcp_responses_collapsed = 10;
|
||||
optional string mcp_display_mode = 11;
|
||||
optional int32 terminal_output_line_limit = 12;
|
||||
optional PlanActMode mode = 13;
|
||||
optional string preferred_language = 14;
|
||||
optional string openai_reasoning_effort = 15;
|
||||
}
|
||||
|
||||
// Complete API Configuration message
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import { SapAiCoreHandler } from "./providers/sapaicore"
|
||||
import { ClaudeCodeHandler } from "./providers/claude-code"
|
||||
import { MoonshotHandler } from "./providers/moonshot"
|
||||
import { GroqHandler } from "./providers/groq"
|
||||
import { Mode } from "../shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { HuggingFaceHandler } from "./providers/huggingface"
|
||||
import { HuaweiCloudMaaSHandler } from "./providers/huawei-cloud-maas"
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ClineAccountService } from "@services/account/ClineAccountService"
|
||||
import { McpHub } from "@services/mcp/McpHub"
|
||||
import { ApiProvider, ModelInfo } from "@shared/api"
|
||||
import { ChatContent } from "@shared/ChatContent"
|
||||
import { ChatSettings, Mode, StoredChatSettings } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { ClineRulesToggles } from "@shared/cline-rules"
|
||||
import { ExtensionMessage, ExtensionState, Platform } from "@shared/ExtensionMessage"
|
||||
import { HistoryItem } from "@shared/HistoryItem"
|
||||
@@ -140,7 +140,9 @@ export class Controller {
|
||||
apiConfiguration,
|
||||
autoApprovalSettings,
|
||||
browserSettings,
|
||||
chatSettings: storedChatSettings,
|
||||
preferredLanguage,
|
||||
openaiReasoningEffort,
|
||||
mode,
|
||||
shellIntegrationTimeout,
|
||||
terminalReuseEnabled,
|
||||
terminalOutputLineLimit,
|
||||
@@ -150,15 +152,6 @@ export class Controller {
|
||||
taskHistory,
|
||||
} = await getAllExtensionState(this.context)
|
||||
|
||||
// Get current mode using helper function
|
||||
const currentMode = await this.getCurrentMode()
|
||||
|
||||
// Reconstruct ChatSettings with mode from global state and stored preferences
|
||||
const chatSettings: ChatSettings = {
|
||||
...storedChatSettings, // Spread stored preferences (preferredLanguage, openAIReasoningEffort)
|
||||
mode: currentMode, // Use mode from global state
|
||||
}
|
||||
|
||||
const NEW_USER_TASK_COUNT_THRESHOLD = 10
|
||||
|
||||
// Check if the user has completed enough tasks to no longer be considered a "new user"
|
||||
@@ -185,7 +178,9 @@ export class Controller {
|
||||
apiConfiguration,
|
||||
autoApprovalSettings,
|
||||
browserSettings,
|
||||
chatSettings,
|
||||
preferredLanguage,
|
||||
openaiReasoningEffort,
|
||||
mode,
|
||||
shellIntegrationTimeout,
|
||||
terminalReuseEnabled ?? true,
|
||||
terminalOutputLineLimit ?? 500,
|
||||
@@ -248,28 +243,25 @@ export class Controller {
|
||||
await this.postStateToWebview()
|
||||
}
|
||||
|
||||
async togglePlanActModeWithChatSettings(chatSettings: ChatSettings, chatContent?: ChatContent): Promise<boolean> {
|
||||
const didSwitchToActMode = chatSettings.mode === "act"
|
||||
async togglePlanActMode(modeToSwitchTo: Mode, chatContent?: ChatContent): Promise<boolean> {
|
||||
const didSwitchToActMode = modeToSwitchTo === "act"
|
||||
|
||||
// Store mode to global state
|
||||
await updateGlobalState(this.context, "mode", chatSettings.mode)
|
||||
await updateGlobalState(this.context, "mode", modeToSwitchTo)
|
||||
|
||||
// Capture mode switch telemetry | Capture regardless of if we know the taskId
|
||||
telemetryService.captureModeSwitch(this.task?.taskId ?? "0", chatSettings.mode)
|
||||
telemetryService.captureModeSwitch(this.task?.taskId ?? "0", modeToSwitchTo)
|
||||
|
||||
// Update API handler with new mode (buildApiHandler now selects provider based on mode)
|
||||
if (this.task) {
|
||||
const { apiConfiguration } = await getAllExtensionState(this.context)
|
||||
this.task.api = buildApiHandler({ ...apiConfiguration, taskId: this.task.taskId }, chatSettings.mode)
|
||||
this.task.api = buildApiHandler({ ...apiConfiguration, taskId: this.task.taskId }, modeToSwitchTo)
|
||||
}
|
||||
|
||||
// Save only non-mode properties to global storage
|
||||
const { mode, ...persistentChatSettings }: { mode: string } & StoredChatSettings = chatSettings
|
||||
await updateGlobalState(this.context, "chatSettings", persistentChatSettings)
|
||||
await this.postStateToWebview()
|
||||
|
||||
if (this.task) {
|
||||
this.task.chatSettings = chatSettings
|
||||
this.task.mode = modeToSwitchTo
|
||||
if (this.task.taskState.isAwaitingPlanResponse && didSwitchToActMode) {
|
||||
this.task.taskState.didRespondToPlanAskBySwitchingMode = true
|
||||
// Use chatContent if provided, otherwise use default message
|
||||
@@ -705,7 +697,9 @@ export class Controller {
|
||||
taskHistory,
|
||||
autoApprovalSettings,
|
||||
browserSettings,
|
||||
chatSettings: storedChatSettings,
|
||||
preferredLanguage,
|
||||
openaiReasoningEffort,
|
||||
mode,
|
||||
userInfo,
|
||||
mcpMarketplaceEnabled,
|
||||
mcpDisplayMode,
|
||||
@@ -723,15 +717,6 @@ export class Controller {
|
||||
terminalOutputLineLimit,
|
||||
} = await getAllExtensionState(this.context)
|
||||
|
||||
// Get current mode using helper function
|
||||
const currentMode = await this.getCurrentMode()
|
||||
|
||||
// Reconstruct ChatSettings with mode from global state and stored preferences
|
||||
const chatSettings: ChatSettings = {
|
||||
...storedChatSettings, // Spread stored preferences (preferredLanguage, openAIReasoningEffort)
|
||||
mode: currentMode, // Use mode from global state
|
||||
}
|
||||
|
||||
const localClineRulesToggles =
|
||||
((await getWorkspaceState(this.context, "localClineRulesToggles")) as ClineRulesToggles) || {}
|
||||
|
||||
@@ -758,7 +743,9 @@ export class Controller {
|
||||
platform: process.platform as Platform,
|
||||
autoApprovalSettings,
|
||||
browserSettings,
|
||||
chatSettings,
|
||||
preferredLanguage,
|
||||
openaiReasoningEffort,
|
||||
mode,
|
||||
userInfo,
|
||||
mcpMarketplaceEnabled,
|
||||
mcpDisplayMode,
|
||||
|
||||
@@ -66,9 +66,9 @@ export async function downloadMcp(controller: Controller, request: StringRequest
|
||||
- Once installed, demonstrate the server's capabilities by using one of its tools.
|
||||
Here is the project's README to help you get started:\n\n${mcpDetails.readmeContent}\n${mcpDetails.llmsInstallationContent}`
|
||||
|
||||
const { chatSettings } = await controller.getStateToPostToWebview()
|
||||
if (chatSettings.mode === "plan") {
|
||||
await controller.togglePlanActModeWithChatSettings({ mode: "act" })
|
||||
const { mode } = await controller.getStateToPostToWebview()
|
||||
if (mode === "plan") {
|
||||
await controller.togglePlanActMode("act")
|
||||
}
|
||||
|
||||
// Initialize task and show chat view
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Controller } from ".."
|
||||
import { Boolean } from "@shared/proto/cline/common"
|
||||
import { TogglePlanActModeRequest } from "@shared/proto/cline/state"
|
||||
import {
|
||||
convertProtoChatContentToChatContent,
|
||||
convertProtoChatSettingsToChatSettings,
|
||||
} from "@shared/proto-conversions/state/chat-settings-conversion"
|
||||
|
||||
/**
|
||||
* Toggles between Plan and Act modes
|
||||
* @param controller The controller instance
|
||||
* @param request The request containing the chat settings and optional chat content
|
||||
* @returns An empty response
|
||||
*/
|
||||
export async function togglePlanActMode(controller: Controller, request: TogglePlanActModeRequest): Promise<Boolean> {
|
||||
try {
|
||||
if (!request.chatSettings) {
|
||||
throw new Error("Chat settings are required")
|
||||
}
|
||||
|
||||
const chatSettings = convertProtoChatSettingsToChatSettings(request.chatSettings)
|
||||
const chatContent = request.chatContent ? convertProtoChatContentToChatContent(request.chatContent) : undefined
|
||||
|
||||
// Call the existing controller implementation
|
||||
const sentMessage = await controller.togglePlanActModeWithChatSettings(chatSettings, chatContent)
|
||||
|
||||
return Boolean.create({
|
||||
value: sentMessage,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle Plan/Act mode:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Controller } from ".."
|
||||
import { Boolean } from "@shared/proto/cline/common"
|
||||
import { TogglePlanActModeRequest, PlanActMode } from "@shared/proto/cline/state"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
/**
|
||||
* Toggles between Plan and Act modes
|
||||
* @param controller The controller instance
|
||||
* @param request The request containing the chat settings and optional chat content
|
||||
* @returns An empty response
|
||||
*/
|
||||
export async function togglePlanActModeProto(controller: Controller, request: TogglePlanActModeRequest): Promise<Boolean> {
|
||||
try {
|
||||
let mode: Mode
|
||||
if (request.mode === PlanActMode.PLAN) {
|
||||
mode = "plan"
|
||||
} else if (request.mode === PlanActMode.ACT) {
|
||||
mode = "act"
|
||||
} else {
|
||||
throw new Error(`Invalid mode value: ${request.mode}`)
|
||||
}
|
||||
const chatContent = request.chatContent
|
||||
|
||||
// Call the existing controller implementation
|
||||
const sentMessage = await controller.togglePlanActMode(mode, chatContent)
|
||||
|
||||
return Boolean.create({
|
||||
value: sentMessage,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle Plan/Act mode:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Controller } from ".."
|
||||
import { Empty } from "@shared/proto/cline/common"
|
||||
import { UpdateSettingsRequest } from "@shared/proto/cline/state"
|
||||
import { PlanActMode, UpdateSettingsRequest } from "@shared/proto/cline/state"
|
||||
import { updateApiConfiguration } from "../../storage/state"
|
||||
import { buildApiHandler } from "../../../api"
|
||||
import { convertProtoApiConfigurationToApiConfiguration } from "../../../shared/proto-conversions/state/settings-conversion"
|
||||
import { convertProtoChatSettingsToChatSettings } from "../../../shared/proto-conversions/state/chat-settings-conversion"
|
||||
import { TelemetrySetting } from "@/shared/TelemetrySetting"
|
||||
import { convertProtoApiConfigurationToApiConfiguration } from "@shared/proto-conversions/state/settings-conversion"
|
||||
import { TelemetrySetting } from "@shared/TelemetrySetting"
|
||||
import { OpenaiReasoningEffort } from "@shared/storage/types"
|
||||
|
||||
/**
|
||||
* Updates multiple extension settings in a single request
|
||||
@@ -56,22 +56,26 @@ export async function updateSettings(controller: Controller, request: UpdateSett
|
||||
await controller.context.globalState.update("mcpDisplayMode", request.mcpDisplayMode)
|
||||
}
|
||||
|
||||
// Update chat settings
|
||||
if (request.chatSettings) {
|
||||
const chatSettings = convertProtoChatSettingsToChatSettings(request.chatSettings)
|
||||
|
||||
// Store mode to global state
|
||||
if (chatSettings.mode !== undefined) {
|
||||
await controller.context.globalState.update("mode", chatSettings.mode)
|
||||
}
|
||||
|
||||
// Store chat settings (excluding mode) to global state
|
||||
const { mode, ...globalChatSettings } = chatSettings
|
||||
await controller.context.globalState.update("chatSettings", globalChatSettings)
|
||||
|
||||
if (request.mode !== undefined) {
|
||||
const mode = request.mode === PlanActMode.PLAN ? "plan" : "act"
|
||||
if (controller.task) {
|
||||
controller.task.chatSettings = chatSettings
|
||||
controller.task.mode = mode
|
||||
}
|
||||
await controller.context.globalState.update("mode", request.mode)
|
||||
}
|
||||
|
||||
if (request.openaiReasoningEffort !== undefined) {
|
||||
if (controller.task) {
|
||||
controller.task.openaiReasoningEffort = request.openaiReasoningEffort as OpenaiReasoningEffort
|
||||
}
|
||||
await controller.context.globalState.update("openaiReasoningEffort", request.openaiReasoningEffort)
|
||||
}
|
||||
|
||||
if (request.preferredLanguage !== undefined) {
|
||||
if (controller.task) {
|
||||
controller.task.preferredLanguage = request.preferredLanguage
|
||||
}
|
||||
await controller.context.globalState.update("preferredLanguage", request.preferredLanguage)
|
||||
}
|
||||
|
||||
// Update terminal timeout setting
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import * as diff from "diff"
|
||||
import * as path from "path"
|
||||
import { ClineIgnoreController, LOCK_TEXT_SYMBOL } from "../ignore/ClineIgnoreController"
|
||||
import { Mode } from "@/shared/ChatSettings"
|
||||
import { Mode } from "@/shared/storage/types"
|
||||
|
||||
export const formatResponse = {
|
||||
duplicateFileReadNotice: () =>
|
||||
|
||||
@@ -84,7 +84,8 @@ export type GlobalStateKey =
|
||||
| "sapAiResourceGroup"
|
||||
| "claudeCodePath"
|
||||
// Settings around plan/act and ephemeral model configuration
|
||||
| "chatSettings"
|
||||
| "preferredLanguage"
|
||||
| "openaiReasoningEffort"
|
||||
| "mode"
|
||||
// Plan mode configurations
|
||||
| "planModeApiProvider"
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ensureRulesDirectoryExists } from "./disk"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { updateGlobalState, getAllExtensionState, getGlobalState } from "./state"
|
||||
import { GlobalStateKey } from "./state-keys"
|
||||
|
||||
export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionContext) {
|
||||
// Keys to migrate from workspace storage back to global storage
|
||||
@@ -13,7 +12,6 @@ export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionC
|
||||
"apiModelId",
|
||||
"thinkingBudgetTokens",
|
||||
"reasoningEffort",
|
||||
"chatSettings",
|
||||
"vsCodeLmModelSelector",
|
||||
|
||||
// Provider-specific model keys
|
||||
@@ -136,43 +134,6 @@ export async function migrateCustomInstructionsToGlobalRules(context: vscode.Ext
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateModeFromWorkspaceStorageToControllerState(context: vscode.ExtensionContext) {
|
||||
try {
|
||||
// Check legacy workspace storage (use raw methods since chatSettings is now global)
|
||||
const workspaceChatSettings = (await context.workspaceState.get("chatSettings")) as any
|
||||
|
||||
if (workspaceChatSettings && typeof workspaceChatSettings === "object" && "mode" in workspaceChatSettings) {
|
||||
console.log("Cleaning up mode from legacy workspace storage...")
|
||||
|
||||
// Remove mode property from chatSettings
|
||||
const { mode, ...cleanedChatSettings } = workspaceChatSettings
|
||||
|
||||
// Save cleaned chatSettings back to workspace storage (will be migrated later)
|
||||
await context.workspaceState.update("chatSettings", cleanedChatSettings)
|
||||
|
||||
console.log("Successfully removed mode from legacy workspace storage chatSettings")
|
||||
}
|
||||
|
||||
// Also check global storage for any mode cleanup needed
|
||||
const globalChatSettings = (await context.globalState.get("chatSettings")) as any
|
||||
|
||||
if (globalChatSettings && typeof globalChatSettings === "object" && "mode" in globalChatSettings) {
|
||||
console.log("Cleaning up mode from global storage...")
|
||||
|
||||
// Remove mode property from chatSettings
|
||||
const { mode, ...cleanedChatSettings } = globalChatSettings
|
||||
|
||||
// Save cleaned chatSettings back to global storage
|
||||
await updateGlobalState(context, "chatSettings", cleanedChatSettings)
|
||||
|
||||
console.log("Successfully removed mode from global storage chatSettings")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to cleanup mode from storage:", error)
|
||||
// Continue execution - migration failure shouldn't break extension startup
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateLegacyApiConfigurationToModeSpecific(context: vscode.ExtensionContext) {
|
||||
try {
|
||||
// Check if migration is needed - if planModeApiProvider already exists, skip migration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as vscode from "vscode"
|
||||
import { DEFAULT_CHAT_SETTINGS, Mode } from "@shared/ChatSettings"
|
||||
import { Mode, OpenaiReasoningEffort } from "@shared/storage/types"
|
||||
import { DEFAULT_BROWSER_SETTINGS } from "@shared/BrowserSettings"
|
||||
import { DEFAULT_AUTO_APPROVAL_SETTINGS } from "@shared/AutoApprovalSettings"
|
||||
import { GlobalStateKey, LocalStateKey, SecretKey } from "./state-keys"
|
||||
@@ -7,7 +7,6 @@ import { ApiConfiguration, ApiProvider, BedrockModelId, ModelInfo } from "@share
|
||||
import { HistoryItem } from "@shared/HistoryItem"
|
||||
import { AutoApprovalSettings } from "@shared/AutoApprovalSettings"
|
||||
import { BrowserSettings } from "@shared/BrowserSettings"
|
||||
import { StoredChatSettings } from "@shared/ChatSettings"
|
||||
import { TelemetrySetting } from "@shared/TelemetrySetting"
|
||||
import { UserInfo } from "@shared/UserInfo"
|
||||
import { ClineRulesToggles } from "@shared/cline-rules"
|
||||
@@ -110,7 +109,6 @@ export async function getWorkspaceState(context: vscode.ExtensionContext, key: L
|
||||
}
|
||||
|
||||
export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
const firstBatchStart = performance.now()
|
||||
const [
|
||||
isNewUser,
|
||||
welcomeViewCompleted,
|
||||
@@ -275,10 +273,10 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
|
||||
const localClineRulesToggles = (await getWorkspaceState(context, "localClineRulesToggles")) as ClineRulesToggles
|
||||
|
||||
const secondBatchStart = performance.now()
|
||||
const [
|
||||
chatSettings,
|
||||
currentMode,
|
||||
preferredLanguage,
|
||||
openaiReasoningEffort,
|
||||
mode,
|
||||
// Plan mode configurations
|
||||
planModeApiProvider,
|
||||
planModeApiModelId,
|
||||
@@ -334,7 +332,8 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
actModeHuaweiCloudMaasModelId,
|
||||
actModeHuaweiCloudMaasModelInfo,
|
||||
] = await Promise.all([
|
||||
getGlobalState(context, "chatSettings") as Promise<StoredChatSettings | undefined>,
|
||||
getGlobalState(context, "preferredLanguage") as Promise<string | undefined>,
|
||||
getGlobalState(context, "openaiReasoningEffort") as Promise<OpenaiReasoningEffort | undefined>,
|
||||
getGlobalState(context, "mode") as Promise<Mode | undefined>,
|
||||
// Plan mode configurations
|
||||
getGlobalState(context, "planModeApiProvider") as Promise<ApiProvider | undefined>,
|
||||
@@ -392,7 +391,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
getGlobalState(context, "actModeHuaweiCloudMaasModelInfo") as Promise<ModelInfo | undefined>,
|
||||
])
|
||||
|
||||
const processingStart = performance.now()
|
||||
let apiProvider: ApiProvider
|
||||
if (planModeApiProvider) {
|
||||
apiProvider = planModeApiProvider
|
||||
@@ -554,11 +552,9 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
globalClineRulesToggles: globalClineRulesToggles || {},
|
||||
localClineRulesToggles: localClineRulesToggles || {},
|
||||
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)
|
||||
chatSettings: {
|
||||
...DEFAULT_CHAT_SETTINGS, // Apply defaults first
|
||||
...(chatSettings || {}), // Spread fetched global chatSettings, which includes preferredLanguage, and openAIReasoningEffort
|
||||
mode: currentMode || "act", // Merge mode from global state
|
||||
},
|
||||
preferredLanguage: preferredLanguage || "English",
|
||||
openaiReasoningEffort: (openaiReasoningEffort as OpenaiReasoningEffort) || "medium",
|
||||
mode: mode || "act",
|
||||
userInfo,
|
||||
mcpMarketplaceEnabled: mcpMarketplaceEnabled,
|
||||
mcpDisplayMode: mcpDisplayMode ?? DEFAULT_MCP_DISPLAY_MODE,
|
||||
|
||||
@@ -54,7 +54,7 @@ import { TaskState } from "./TaskState"
|
||||
import { MessageStateHandler } from "./message-state"
|
||||
import { AutoApprove } from "./tools/autoApprove"
|
||||
import { showNotificationForApprovalIfAutoApprovalEnabled } from "./utils"
|
||||
import { ChatSettings } from "@/shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
export class ToolExecutor {
|
||||
private autoApprover: AutoApprove
|
||||
@@ -91,7 +91,7 @@ export class ToolExecutor {
|
||||
private browserSettings: BrowserSettings,
|
||||
private cwd: string,
|
||||
private taskId: string,
|
||||
private chatSettings: ChatSettings,
|
||||
private mode: Mode,
|
||||
|
||||
// Callbacks to the Task (Entity)
|
||||
private say: (
|
||||
@@ -1919,7 +1919,7 @@ export class ToolExecutor {
|
||||
const clineVersion =
|
||||
vscode.extensions.getExtension("saoudrizwan.claude-dev")?.packageJSON.version || "Unknown"
|
||||
const systemInfo = `VSCode: ${vscode.version}, Node.js: ${process.version}, Architecture: ${os.arch()}`
|
||||
const currentMode = this.chatSettings.mode
|
||||
const currentMode = this.mode
|
||||
const apiProvider =
|
||||
currentMode === "plan"
|
||||
? await getGlobalState(this.context, "planModeApiProvider")
|
||||
|
||||
+21
-27
@@ -19,7 +19,6 @@ import { ApiConfiguration } from "@shared/api"
|
||||
import { findLast, findLastIndex } from "@shared/array"
|
||||
import { AutoApprovalSettings } from "@shared/AutoApprovalSettings"
|
||||
import { BrowserSettings } from "@shared/BrowserSettings"
|
||||
import { ChatSettings } from "@shared/ChatSettings"
|
||||
import { combineApiRequests } from "@shared/combineApiRequests"
|
||||
import { combineCommandSequences } from "@shared/combineCommandSequences"
|
||||
import { ClineApiReqCancelReason, ClineApiReqInfo, ClineAsk, ClineMessage, ClineSay } from "@shared/ExtensionMessage"
|
||||
@@ -86,6 +85,7 @@ import { MessageStateHandler } from "./message-state"
|
||||
import { TaskState } from "./TaskState"
|
||||
import { ToolExecutor } from "./ToolExecutor"
|
||||
import { updateApiReqMsg } from "./utils"
|
||||
import { Mode, OpenaiReasoningEffort } from "@shared/storage/types"
|
||||
import { ShowMessageType } from "@/shared/proto/index.host"
|
||||
|
||||
export const USE_EXPERIMENTAL_CLAUDE4_FEATURES = false
|
||||
@@ -133,7 +133,9 @@ export class Task {
|
||||
// User chat state
|
||||
autoApprovalSettings: AutoApprovalSettings
|
||||
browserSettings: BrowserSettings
|
||||
chatSettings: ChatSettings
|
||||
preferredLanguage: string
|
||||
openaiReasoningEffort: OpenaiReasoningEffort
|
||||
mode: Mode
|
||||
|
||||
// Message and conversation state
|
||||
messageStateHandler: MessageStateHandler
|
||||
@@ -148,7 +150,9 @@ export class Task {
|
||||
apiConfiguration: ApiConfiguration,
|
||||
autoApprovalSettings: AutoApprovalSettings,
|
||||
browserSettings: BrowserSettings,
|
||||
chatSettings: ChatSettings,
|
||||
preferredLanguage: string,
|
||||
openaiReasoningEffort: OpenaiReasoningEffort,
|
||||
mode: Mode,
|
||||
shellIntegrationTimeout: number,
|
||||
terminalReuseEnabled: boolean,
|
||||
terminalOutputLineLimit: number,
|
||||
@@ -193,7 +197,9 @@ export class Task {
|
||||
this.diffViewProvider = HostProvider.get().createDiffViewProvider()
|
||||
this.autoApprovalSettings = autoApprovalSettings
|
||||
this.browserSettings = browserSettings
|
||||
this.chatSettings = chatSettings
|
||||
this.preferredLanguage = preferredLanguage
|
||||
this.openaiReasoningEffort = openaiReasoningEffort
|
||||
this.mode = mode
|
||||
this.enableCheckpoints = enableCheckpointsSetting
|
||||
this.cwd = cwd
|
||||
|
||||
@@ -267,19 +273,18 @@ export class Task {
|
||||
},
|
||||
}
|
||||
|
||||
const currentProvider =
|
||||
chatSettings.mode === "plan" ? apiConfiguration.planModeApiProvider : apiConfiguration.actModeApiProvider
|
||||
const currentProvider = this.mode === "plan" ? apiConfiguration.planModeApiProvider : apiConfiguration.actModeApiProvider
|
||||
|
||||
if (currentProvider === "openai" || currentProvider === "openai-native") {
|
||||
if (chatSettings.mode === "plan") {
|
||||
effectiveApiConfiguration.planModeReasoningEffort = chatSettings.openAIReasoningEffort
|
||||
if (this.mode === "plan") {
|
||||
effectiveApiConfiguration.planModeReasoningEffort = this.openaiReasoningEffort
|
||||
} else {
|
||||
effectiveApiConfiguration.actModeReasoningEffort = chatSettings.openAIReasoningEffort
|
||||
effectiveApiConfiguration.actModeReasoningEffort = this.openaiReasoningEffort
|
||||
}
|
||||
}
|
||||
|
||||
// Now that taskId is initialized, we can build the API handler
|
||||
this.api = buildApiHandler(effectiveApiConfiguration, chatSettings.mode)
|
||||
this.api = buildApiHandler(effectiveApiConfiguration, this.mode)
|
||||
|
||||
// Set taskId on browserSession for telemetry tracking
|
||||
this.browserSession.setTaskId(this.taskId)
|
||||
@@ -317,7 +322,7 @@ export class Task {
|
||||
this.browserSettings,
|
||||
cwd,
|
||||
this.taskId,
|
||||
this.chatSettings,
|
||||
this.mode,
|
||||
this.say.bind(this),
|
||||
this.ask.bind(this),
|
||||
this.saveCheckpoint.bind(this),
|
||||
@@ -1178,7 +1183,7 @@ export class Task {
|
||||
const hasPendingFileContextWarnings = pendingContextWarning && pendingContextWarning.length > 0
|
||||
|
||||
const [taskResumptionMessage, userResponseMessage] = formatResponse.taskResumption(
|
||||
this.chatSettings?.mode === "plan" ? "plan" : "act",
|
||||
this.mode === "plan" ? "plan" : "act",
|
||||
agoText,
|
||||
this.cwd,
|
||||
wasRecent,
|
||||
@@ -1654,20 +1659,10 @@ export class Task {
|
||||
}
|
||||
}
|
||||
|
||||
private async migratePreferredLanguageToolSetting(): Promise<void> {
|
||||
const config = vscode.workspace.getConfiguration("cline")
|
||||
const preferredLanguage = config.get<LanguageDisplay>("preferredLanguage")
|
||||
if (preferredLanguage !== undefined) {
|
||||
this.chatSettings.preferredLanguage = preferredLanguage
|
||||
// Remove from VSCode configuration
|
||||
await config.update("preferredLanguage", undefined, true)
|
||||
}
|
||||
}
|
||||
|
||||
private async getCurrentProviderInfo(): Promise<{ modelId: string; providerId: string }> {
|
||||
const modelId = this.api.getModel()?.id
|
||||
const providerId =
|
||||
this.chatSettings.mode === "plan"
|
||||
this.mode === "plan"
|
||||
? ((await getGlobalState(this.getContext(), "planModeApiProvider")) as string)
|
||||
: ((await getGlobalState(this.getContext(), "actModeApiProvider")) as string)
|
||||
return { modelId, providerId }
|
||||
@@ -1690,8 +1685,7 @@ export class Task {
|
||||
const isNextGenModel = isClaude4ModelFamily(this.api) || isGemini2dot5ModelFamily(this.api)
|
||||
let systemPrompt = await SYSTEM_PROMPT(this.cwd, supportsBrowserUse, this.mcpHub, this.browserSettings, isNextGenModel)
|
||||
|
||||
await this.migratePreferredLanguageToolSetting()
|
||||
const preferredLanguage = getLanguageKey(this.chatSettings.preferredLanguage as LanguageDisplay)
|
||||
const preferredLanguage = getLanguageKey(this.preferredLanguage as LanguageDisplay)
|
||||
const preferredLanguageInstructions =
|
||||
preferredLanguage && preferredLanguage !== DEFAULT_LANGUAGE_SETTINGS
|
||||
? `# Preferred Language\n\nSpeak in ${preferredLanguage}.`
|
||||
@@ -2000,7 +1994,7 @@ export class Task {
|
||||
const { modelId, providerId } = await this.getCurrentProviderInfo()
|
||||
if (providerId && modelId) {
|
||||
try {
|
||||
await this.modelContextTracker.recordModelUsage(providerId, modelId, this.chatSettings.mode)
|
||||
await this.modelContextTracker.recordModelUsage(providerId, modelId, this.mode)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -2771,7 +2765,7 @@ export class Task {
|
||||
details += `\n${lastApiReqTotalTokens.toLocaleString()} / ${(contextWindow / 1000).toLocaleString()}K tokens used (${usagePercentage}%)`
|
||||
|
||||
details += "\n\n# Current Mode"
|
||||
if (this.chatSettings.mode === "plan") {
|
||||
if (this.mode === "plan") {
|
||||
details += "\nPLAN MODE\n" + formatResponse.planModeInstructions()
|
||||
} else {
|
||||
details += "\nACT MODE"
|
||||
|
||||
@@ -14,8 +14,6 @@ import { sendMcpButtonClickedEvent } from "./core/controller/ui/subscribeToMcpBu
|
||||
import { sendSettingsButtonClickedEvent } from "./core/controller/ui/subscribeToSettingsButtonClicked"
|
||||
import {
|
||||
migrateCustomInstructionsToGlobalRules,
|
||||
migrateLegacyApiConfigurationToModeSpecific,
|
||||
migrateModeFromWorkspaceStorageToControllerState,
|
||||
migrateWelcomeViewCompleted,
|
||||
migrateWorkspaceToGlobalStorage,
|
||||
} from "./core/storage/state-migrations"
|
||||
@@ -60,18 +58,12 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// Migrate custom instructions to global Cline rules (one-time cleanup)
|
||||
await migrateCustomInstructionsToGlobalRules(context)
|
||||
|
||||
// Migrate mode from workspace storage to controller state (one-time cleanup)
|
||||
await migrateModeFromWorkspaceStorageToControllerState(context)
|
||||
|
||||
// Migrate welcomeViewCompleted setting based on existing API keys (one-time cleanup)
|
||||
await migrateWelcomeViewCompleted(context)
|
||||
|
||||
// Migrate workspace storage values back to global storage (reverting previous migration)
|
||||
await migrateWorkspaceToGlobalStorage(context)
|
||||
|
||||
// Migrate legacy API configuration to mode-specific keys (one-time migration)
|
||||
await migrateLegacyApiConfigurationToModeSpecific(context)
|
||||
|
||||
// Clean up orphaned file context warnings (startup cleanup)
|
||||
await FileContextTracker.cleanupOrphanedWarnings(context)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { version as extensionVersion } from "../../../../package.json"
|
||||
import type { TaskFeedbackType } from "@shared/WebviewMessage"
|
||||
import type { BrowserSettings } from "@shared/BrowserSettings"
|
||||
import { posthogClientProvider } from "../PostHogClientProvider"
|
||||
import { Mode } from "@/shared/ChatSettings"
|
||||
import { Mode } from "@/shared/storage/types"
|
||||
|
||||
/**
|
||||
* TelemetryService handles telemetry event tracking for the Cline extension
|
||||
|
||||
@@ -282,10 +282,10 @@ export function createTestServer(webviewProvider?: WebviewProvider): http.Server
|
||||
}
|
||||
|
||||
// Ensure we're in Act mode before initiating the task
|
||||
const { chatSettings } = await visibleWebview.controller.getStateToPostToWebview()
|
||||
if (chatSettings.mode === "plan") {
|
||||
const { mode } = await visibleWebview.controller.getStateToPostToWebview()
|
||||
if (mode === "plan") {
|
||||
// Switch to Act mode if currently in Plan mode
|
||||
await visibleWebview.controller.togglePlanActModeWithChatSettings({ mode: "act" })
|
||||
await visibleWebview.controller.togglePlanActMode("act")
|
||||
}
|
||||
|
||||
// Initialize tool call tracker
|
||||
@@ -612,7 +612,7 @@ async function autoRespondToAsk(webviewProvider: WebviewProvider, askType: Cline
|
||||
try {
|
||||
if (webviewProvider.controller) {
|
||||
Logger.log("Auto-toggling to Act mode from Plan mode")
|
||||
await webviewProvider.controller.togglePlanActModeWithChatSettings({ mode: "act" })
|
||||
await webviewProvider.controller.togglePlanActMode("act")
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.log(`Error toggling to Act mode: ${error}`)
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
export type OpenAIReasoningEffort = "low" | "medium" | "high"
|
||||
|
||||
export type Mode = "plan" | "act"
|
||||
|
||||
export interface ChatSettings {
|
||||
mode: Mode
|
||||
preferredLanguage?: string
|
||||
openAIReasoningEffort?: OpenAIReasoningEffort
|
||||
}
|
||||
|
||||
export type PartialChatSettings = Partial<ChatSettings>
|
||||
|
||||
// Type for chat settings stored in workspace (excludes in-memory mode)
|
||||
export type StoredChatSettings = Omit<ChatSettings, "mode">
|
||||
|
||||
export const DEFAULT_CHAT_SETTINGS: ChatSettings = {
|
||||
mode: "act",
|
||||
preferredLanguage: "English",
|
||||
openAIReasoningEffort: "medium",
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ApiConfiguration } from "./api"
|
||||
import { AutoApprovalSettings } from "./AutoApprovalSettings"
|
||||
import { BrowserSettings } from "./BrowserSettings"
|
||||
import { ChatSettings } from "./ChatSettings"
|
||||
import { Mode, OpenaiReasoningEffort } from "./storage/types"
|
||||
import { HistoryItem } from "./HistoryItem"
|
||||
import { TelemetrySetting } from "./TelemetrySetting"
|
||||
import { ClineRulesToggles } from "./cline-rules"
|
||||
@@ -33,7 +33,9 @@ export interface ExtensionState {
|
||||
autoApprovalSettings: AutoApprovalSettings
|
||||
browserSettings: BrowserSettings
|
||||
remoteBrowserHost?: string
|
||||
chatSettings: ChatSettings
|
||||
preferredLanguage?: string
|
||||
openaiReasoningEffort?: OpenaiReasoningEffort
|
||||
mode: Mode
|
||||
checkpointTrackerErrorMessage?: string
|
||||
clineMessages: ClineMessage[]
|
||||
currentTaskItem?: HistoryItem
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ApiConfiguration } from "./api"
|
||||
import { BrowserSettings } from "./BrowserSettings"
|
||||
import { ChatSettings } from "./ChatSettings"
|
||||
import { UserInfo } from "./UserInfo"
|
||||
import { ChatContent } from "./ChatContent"
|
||||
import { TelemetrySetting } from "./TelemetrySetting"
|
||||
@@ -23,7 +22,6 @@ export interface WebviewMessage {
|
||||
bool?: boolean
|
||||
number?: number
|
||||
browserSettings?: BrowserSettings
|
||||
chatSettings?: ChatSettings
|
||||
chatContent?: ChatContent
|
||||
mcpId?: string
|
||||
timeout?: number
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { ChatContent } from "@shared/ChatContent"
|
||||
import { ChatSettings } from "@shared/ChatSettings"
|
||||
import { ChatContent as ProtoChatContent, ChatSettings as ProtoChatSettings, PlanActMode } from "@shared/proto/cline/state"
|
||||
|
||||
/**
|
||||
* Converts domain ChatSettings objects to proto ChatSettings objects
|
||||
*/
|
||||
export function convertChatSettingsToProtoChatSettings(chatSettings: ChatSettings): ProtoChatSettings {
|
||||
return ProtoChatSettings.create({
|
||||
mode: chatSettings.mode === "plan" ? PlanActMode.PLAN : PlanActMode.ACT,
|
||||
preferredLanguage: chatSettings.preferredLanguage,
|
||||
openAiReasoningEffort: chatSettings.openAIReasoningEffort,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts proto ChatSettings objects to domain ChatSettings objects
|
||||
*/
|
||||
export function convertProtoChatSettingsToChatSettings(protoChatSettings: ProtoChatSettings): ChatSettings {
|
||||
return {
|
||||
mode: protoChatSettings.mode === PlanActMode.PLAN ? "plan" : "act",
|
||||
preferredLanguage: protoChatSettings.preferredLanguage,
|
||||
openAIReasoningEffort: protoChatSettings.openAiReasoningEffort as "low" | "medium" | "high" | undefined,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts domain ChatContent objects to proto ChatContent objects
|
||||
*/
|
||||
export function convertChatContentToProtoChatContent(chatContent?: ChatContent): ProtoChatContent | undefined {
|
||||
if (!chatContent) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return ProtoChatContent.create({
|
||||
message: chatContent.message,
|
||||
images: chatContent.images || [],
|
||||
files: chatContent.files || [],
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts proto ChatContent objects to domain ChatContent objects
|
||||
*/
|
||||
export function convertProtoChatContentToChatContent(protoChatContent?: ProtoChatContent): ChatContent | undefined {
|
||||
if (!protoChatContent) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
message: protoChatContent.message,
|
||||
images: protoChatContent.images || [],
|
||||
files: protoChatContent.files || [],
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
import { ApiConfiguration, ApiProvider, BedrockModelId } from "@shared/api"
|
||||
import { ChatSettings } from "@shared/ChatSettings"
|
||||
import {
|
||||
ApiConfiguration as ProtoApiConfiguration,
|
||||
ChatSettings as ProtoChatSettings,
|
||||
PlanActMode,
|
||||
} from "@shared/proto/cline/state"
|
||||
import { ApiConfiguration as ProtoApiConfiguration } from "@shared/proto/cline/state"
|
||||
|
||||
/**
|
||||
* Converts domain ApiConfiguration objects to proto ApiConfiguration objects
|
||||
@@ -279,25 +274,3 @@ export function convertProtoApiConfigurationToApiConfiguration(protoConfig: Prot
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts domain ChatSettings objects to proto ChatSettings objects
|
||||
*/
|
||||
export function convertChatSettingsToProtoChatSettings(chatSettings: ChatSettings): ProtoChatSettings {
|
||||
return ProtoChatSettings.create({
|
||||
mode: chatSettings.mode === "plan" ? PlanActMode.PLAN : PlanActMode.ACT,
|
||||
preferredLanguage: chatSettings.preferredLanguage,
|
||||
openAiReasoningEffort: chatSettings.openAIReasoningEffort,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts proto ChatSettings objects to domain ChatSettings objects
|
||||
*/
|
||||
export function convertProtoChatSettingsToChatSettings(protoChatSettings: ProtoChatSettings): ChatSettings {
|
||||
return {
|
||||
mode: protoChatSettings.mode === PlanActMode.PLAN ? "plan" : "act",
|
||||
preferredLanguage: protoChatSettings.preferredLanguage,
|
||||
openAIReasoningEffort: protoChatSettings.openAiReasoningEffort as "low" | "medium" | "high" | undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export type OpenaiReasoningEffort = "low" | "medium" | "high"
|
||||
|
||||
export type Mode = "plan" | "act"
|
||||
@@ -1,154 +0,0 @@
|
||||
import * as vscode from "vscode"
|
||||
import { describe, it, beforeEach, afterEach } from "mocha"
|
||||
import { strict as assert } from "assert"
|
||||
describe("Chat Integration Tests", () => {
|
||||
let panel: vscode.WebviewPanel
|
||||
let disposables: vscode.Disposable[] = []
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create VSCode webview panel
|
||||
panel = vscode.window.createWebviewPanel("testWebview", "Chat Test", vscode.ViewColumn.One, {
|
||||
enableScripts: true,
|
||||
retainContextWhenHidden: true,
|
||||
})
|
||||
|
||||
// Set up minimal test webview
|
||||
panel.webview.html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
const vscode = acquireVsCodeApi();
|
||||
window.addEventListener('message', event => {
|
||||
const message = event.data;
|
||||
switch (message.type) {
|
||||
case 'sendMessage':
|
||||
vscode.postMessage({ type: 'newTask', text: message.text });
|
||||
break;
|
||||
case 'toggleMode':
|
||||
vscode.postMessage({
|
||||
type: 'togglePlanActMode',
|
||||
chatSettings: { mode: 'act' },
|
||||
chatContent: {
|
||||
message: "message test",
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'primaryButtonClick':
|
||||
vscode.postMessage({
|
||||
type: 'grpc_request',
|
||||
grpc_request: {
|
||||
service: 'cline.TaskService',
|
||||
method: 'askResponse',
|
||||
message: {
|
||||
responseType: 'yesButtonClicked'
|
||||
},
|
||||
request_id: 'test-request-id',
|
||||
is_streaming: false
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="test-webview"></div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
panel.dispose()
|
||||
disposables.forEach((d) => d.dispose())
|
||||
disposables = []
|
||||
})
|
||||
|
||||
it("should send chat messages", async () => {
|
||||
// Set up message listener
|
||||
const messagePromise = new Promise<any>((resolve) => {
|
||||
panel.webview.onDidReceiveMessage((message) => {
|
||||
if (message.type === "newTask") {
|
||||
resolve(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Trigger send message
|
||||
await panel.webview.postMessage({
|
||||
type: "sendMessage",
|
||||
text: "Create a hello world app",
|
||||
})
|
||||
|
||||
// Verify message was sent
|
||||
const message = await messagePromise
|
||||
assert.equal(message.type, "newTask")
|
||||
assert.equal(message.text, "Create a hello world app")
|
||||
})
|
||||
|
||||
it("should toggle between plan and act modes", async () => {
|
||||
// Set up state change listener
|
||||
const stateChangePromise = new Promise<any>((resolve) => {
|
||||
panel.webview.onDidReceiveMessage((message) => {
|
||||
if (message.type === "togglePlanActMode") {
|
||||
resolve(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Trigger mode toggle
|
||||
await panel.webview.postMessage({ type: "toggleMode" })
|
||||
|
||||
// Verify mode changed
|
||||
const stateChange = await stateChangePromise
|
||||
assert.equal(stateChange.chatSettings.mode, "act")
|
||||
})
|
||||
|
||||
it("should toggle between plan and act modes with messages", async () => {
|
||||
// Set up state change listener
|
||||
const stateChangePromise = new Promise<any>((resolve) => {
|
||||
panel.webview.onDidReceiveMessage((message) => {
|
||||
if (message.type === "togglePlanActMode") {
|
||||
resolve(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Trigger mode toggle
|
||||
await panel.webview.postMessage({ type: "toggleMode" })
|
||||
|
||||
// Verify mode changed
|
||||
const stateChange = await stateChangePromise
|
||||
assert.equal(stateChange.chatSettings.mode, "act")
|
||||
assert.equal(stateChange.chatContent.message, "message test")
|
||||
})
|
||||
|
||||
it("should handle tool approval flow", async () => {
|
||||
// Set up approval listener for gRPC request
|
||||
const approvalPromise = new Promise<any>((resolve) => {
|
||||
panel.webview.onDidReceiveMessage((message) => {
|
||||
if (
|
||||
message.type === "grpc_request" &&
|
||||
message.grpc_request?.service === "cline.TaskService" &&
|
||||
message.grpc_request?.method === "askResponse"
|
||||
) {
|
||||
resolve(message)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Trigger tool approval
|
||||
await panel.webview.postMessage({
|
||||
type: "primaryButtonClick",
|
||||
})
|
||||
|
||||
// Verify gRPC request was sent with correct parameters
|
||||
const response = await approvalPromise
|
||||
assert.equal(response.type, "grpc_request")
|
||||
assert.equal(response.grpc_request.service, "cline.TaskService")
|
||||
assert.equal(response.grpc_request.method, "askResponse")
|
||||
assert.equal(response.grpc_request.message.responseType, "yesButtonClicked")
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { ChatSettings } from "@shared/ChatSettings"
|
||||
import { mentionRegex, mentionRegexGlobal } from "@shared/context-mentions"
|
||||
import { EmptyRequest, StringRequest } from "@shared/proto/cline/common"
|
||||
import { FileSearchRequest, RelativePathsRequest } from "@shared/proto/cline/file"
|
||||
@@ -44,6 +43,7 @@ import {
|
||||
import { validateApiConfiguration, validateModelId } from "@/utils/validate"
|
||||
import ClineRulesToggleModal from "../cline-rules/ClineRulesToggleModal"
|
||||
import ServersToggleModal from "./ServersToggleModal"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
const { MAX_IMAGES_AND_FILES_PER_MESSAGE } = CHAT_CONSTANTS
|
||||
|
||||
@@ -277,15 +277,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const {
|
||||
filePaths,
|
||||
chatSettings,
|
||||
apiConfiguration,
|
||||
openRouterModels,
|
||||
platform,
|
||||
localWorkflowToggles,
|
||||
globalWorkflowToggles,
|
||||
} = useExtensionState()
|
||||
const { filePaths, mode, apiConfiguration, openRouterModels, platform, localWorkflowToggles, globalWorkflowToggles } =
|
||||
useExtensionState()
|
||||
const [isTextAreaFocused, setIsTextAreaFocused] = useState(false)
|
||||
const [isDraggingOver, setIsDraggingOver] = useState(false)
|
||||
const [gitCommits, setGitCommits] = useState<GitCommit[]>([])
|
||||
@@ -315,7 +308,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
const buttonRef = useRef<HTMLDivElement>(null)
|
||||
const [arrowPosition, setArrowPosition] = useState(0)
|
||||
const [menuPosition, setMenuPosition] = useState(0)
|
||||
const [shownTooltipMode, setShownTooltipMode] = useState<ChatSettings["mode"] | null>(null)
|
||||
const [shownTooltipMode, setShownTooltipMode] = useState<Mode | null>(null)
|
||||
const [pendingInsertions, setPendingInsertions] = useState<string[]>([])
|
||||
const shiftHoldTimerRef = useRef<NodeJS.Timeout | null>(null)
|
||||
const [showUnsupportedFileError, setShowUnsupportedFileError] = useState(false)
|
||||
@@ -971,8 +964,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
|
||||
// Separate the API config submission logic
|
||||
const submitApiConfig = useCallback(async () => {
|
||||
const apiValidationResult = validateApiConfiguration(chatSettings.mode, apiConfiguration)
|
||||
const modelIdValidationResult = validateModelId(chatSettings.mode, apiConfiguration, openRouterModels)
|
||||
const apiValidationResult = validateApiConfiguration(mode, apiConfiguration)
|
||||
const modelIdValidationResult = validateModelId(mode, apiConfiguration, openRouterModels)
|
||||
|
||||
if (!apiValidationResult && !modelIdValidationResult && apiConfiguration) {
|
||||
try {
|
||||
@@ -1004,18 +997,14 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
changeModeDelay = 250 // necessary to let the api config update (we send message and wait for it to be saved) FIXME: this is a hack and we ideally should check for api config changes, then wait for it to be saved, before switching modes
|
||||
}
|
||||
setTimeout(async () => {
|
||||
const newMode = chatSettings.mode === "plan" ? PlanActMode.ACT : PlanActMode.PLAN
|
||||
const response = await StateServiceClient.togglePlanActMode(
|
||||
const convertedProtoMode = mode === "plan" ? PlanActMode.ACT : PlanActMode.PLAN
|
||||
const response = await StateServiceClient.togglePlanActModeProto(
|
||||
TogglePlanActModeRequest.create({
|
||||
chatSettings: {
|
||||
mode: newMode,
|
||||
preferredLanguage: chatSettings.preferredLanguage,
|
||||
openAiReasoningEffort: chatSettings.openAIReasoningEffort,
|
||||
},
|
||||
mode: convertedProtoMode,
|
||||
chatContent: {
|
||||
message: inputValue.trim() ? inputValue : undefined,
|
||||
images: selectedImages.length > 0 ? selectedImages : undefined,
|
||||
files: selectedFiles.length > 0 ? selectedFiles : undefined,
|
||||
images: selectedImages,
|
||||
files: selectedFiles,
|
||||
},
|
||||
}),
|
||||
)
|
||||
@@ -1027,7 +1016,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
textAreaRef.current?.focus()
|
||||
}, 100)
|
||||
}, changeModeDelay)
|
||||
}, [chatSettings.mode, showModelSelector, submitApiConfig, inputValue, selectedImages, selectedFiles])
|
||||
}, [mode, showModelSelector, submitApiConfig, inputValue, selectedImages, selectedFiles])
|
||||
|
||||
useShortcut("Meta+Shift+a", onModeToggle, { disableTextInputs: false }) // important that we don't disable the text input here
|
||||
|
||||
@@ -1094,7 +1083,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
|
||||
// Get model display name
|
||||
const modelDisplayName = useMemo(() => {
|
||||
const { selectedProvider, selectedModelId } = normalizeApiConfiguration(apiConfiguration, chatSettings.mode)
|
||||
const { selectedProvider, selectedModelId } = normalizeApiConfiguration(apiConfiguration, mode)
|
||||
const {
|
||||
vsCodeLmModelSelector,
|
||||
togetherModelId,
|
||||
@@ -1103,7 +1092,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
ollamaModelId,
|
||||
liteLlmModelId,
|
||||
requestyModelId,
|
||||
} = getModeSpecificFields(apiConfiguration, chatSettings.mode)
|
||||
} = getModeSpecificFields(apiConfiguration, mode)
|
||||
const unknownModel = "unknown"
|
||||
if (!apiConfiguration) return unknownModel
|
||||
switch (selectedProvider) {
|
||||
@@ -1130,7 +1119,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
default:
|
||||
return `${selectedProvider}:${selectedModelId}`
|
||||
}
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
}, [apiConfiguration, mode])
|
||||
|
||||
// Calculate arrow position and menu position based on button location
|
||||
useEffect(() => {
|
||||
@@ -1586,7 +1575,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
isDraggingOver && !showUnsupportedFileError // Only show drag outline if not showing error
|
||||
? "2px dashed var(--vscode-focusBorder)"
|
||||
: isTextAreaFocused
|
||||
? `1px solid ${chatSettings.mode === "plan" ? PLAN_MODE_COLOR : "var(--vscode-focusBorder)"}`
|
||||
? `1px solid ${mode === "plan" ? PLAN_MODE_COLOR : "var(--vscode-focusBorder)"}`
|
||||
: "none",
|
||||
outlineOffset: isDraggingOver && !showUnsupportedFileError ? "1px" : "0px", // Add offset for drag-over outline
|
||||
}}
|
||||
@@ -1739,7 +1728,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
apiErrorMessage={undefined}
|
||||
modelIdErrorMessage={undefined}
|
||||
isPopup={true}
|
||||
currentMode={chatSettings.mode}
|
||||
currentMode={mode}
|
||||
/>
|
||||
</ModelSelectorTooltip>
|
||||
)}
|
||||
@@ -1753,19 +1742,19 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
tipText={`In ${shownTooltipMode === "act" ? "Act" : "Plan"} mode, Cline will ${shownTooltipMode === "act" ? "complete the task immediately" : "gather information to architect a plan"}`}
|
||||
hintText={`Toggle w/ ${metaKeyChar}+Shift+A`}>
|
||||
<SwitchContainer data-testid="mode-switch" disabled={false} onClick={onModeToggle}>
|
||||
<Slider isAct={chatSettings.mode === "act"} isPlan={chatSettings.mode === "plan"} />
|
||||
<Slider isAct={mode === "act"} isPlan={mode === "plan"} />
|
||||
<SwitchOption
|
||||
isActive={chatSettings.mode === "plan"}
|
||||
isActive={mode === "plan"}
|
||||
role="switch"
|
||||
aria-checked={chatSettings.mode === "plan"}
|
||||
aria-checked={mode === "plan"}
|
||||
onMouseOver={() => setShownTooltipMode("plan")}
|
||||
onMouseLeave={() => setShownTooltipMode(null)}>
|
||||
Plan
|
||||
</SwitchOption>
|
||||
<SwitchOption
|
||||
isActive={chatSettings.mode === "act"}
|
||||
isActive={mode === "act"}
|
||||
role="switch"
|
||||
aria-checked={chatSettings.mode === "act"}
|
||||
aria-checked={mode === "act"}
|
||||
onMouseOver={() => setShownTooltipMode("act")}
|
||||
onMouseLeave={() => setShownTooltipMode(null)}>
|
||||
Act
|
||||
|
||||
@@ -49,7 +49,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
||||
apiConfiguration,
|
||||
telemetrySetting,
|
||||
navigateToChat,
|
||||
chatSettings,
|
||||
mode,
|
||||
} = useExtensionState()
|
||||
const shouldShowQuickWins = false // !taskHistory || taskHistory.length < QUICK_WINS_HISTORY_THRESHOLD
|
||||
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
|
||||
@@ -202,8 +202,8 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
||||
messageHandlers
|
||||
|
||||
const { selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration, chatSettings.mode)
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
return normalizeApiConfiguration(apiConfiguration, mode)
|
||||
}, [apiConfiguration, mode])
|
||||
|
||||
const selectFilesAndImages = useCallback(async () => {
|
||||
try {
|
||||
|
||||
@@ -43,7 +43,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
onClose,
|
||||
onScrollToMessage,
|
||||
}) => {
|
||||
const { apiConfiguration, currentTaskItem, checkpointTrackerErrorMessage, clineMessages, navigateToSettings, chatSettings } =
|
||||
const { apiConfiguration, currentTaskItem, checkpointTrackerErrorMessage, clineMessages, navigateToSettings, mode } =
|
||||
useExtensionState()
|
||||
const [isTaskExpanded, setIsTaskExpanded] = useState(true)
|
||||
const [isTextExpanded, setIsTextExpanded] = useState(false)
|
||||
@@ -51,10 +51,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
const textContainerRef = useRef<HTMLDivElement>(null)
|
||||
const textRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const { selectedModelInfo } = useMemo(
|
||||
() => normalizeApiConfiguration(apiConfiguration, chatSettings.mode),
|
||||
[apiConfiguration, chatSettings.mode],
|
||||
)
|
||||
const { selectedModelInfo } = useMemo(() => normalizeApiConfiguration(apiConfiguration, mode), [apiConfiguration, mode])
|
||||
const contextWindow = selectedModelInfo?.contextWindow
|
||||
|
||||
// Open task header when checkpoint tracker error message is set
|
||||
@@ -133,7 +130,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
}, [task.text, windowWidth, isTaskExpanded])
|
||||
|
||||
const isCostAvailable = useMemo(() => {
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, chatSettings.mode)
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, mode)
|
||||
const openAiCompatHasPricing =
|
||||
modeFields.apiProvider === "openai" &&
|
||||
modeFields.openAiModelInfo?.inputPrice &&
|
||||
@@ -144,7 +141,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
return (
|
||||
modeFields.apiProvider !== "vscode-lm" && modeFields.apiProvider !== "ollama" && modeFields.apiProvider !== "lmstudio"
|
||||
)
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
}, [apiConfiguration, mode])
|
||||
|
||||
const shouldShowPromptCacheInfo = () => {
|
||||
// Hybrid logic: Show cache info if we have actual cache data,
|
||||
|
||||
@@ -14,27 +14,23 @@ import { PlanActMode, TogglePlanActModeRequest } from "@shared/proto/cline/state
|
||||
|
||||
// Styled component for Act Mode text with more specific styling
|
||||
const ActModeHighlight: React.FC = () => {
|
||||
const { chatSettings } = useExtensionState()
|
||||
const { mode } = useExtensionState()
|
||||
|
||||
return (
|
||||
<span
|
||||
onClick={() => {
|
||||
// Only toggle to Act mode if we're currently in Plan mode
|
||||
if (chatSettings.mode === "plan") {
|
||||
StateServiceClient.togglePlanActMode(
|
||||
if (mode === "plan") {
|
||||
StateServiceClient.togglePlanActModeProto(
|
||||
TogglePlanActModeRequest.create({
|
||||
chatSettings: {
|
||||
mode: PlanActMode.ACT,
|
||||
preferredLanguage: chatSettings.preferredLanguage,
|
||||
openAiReasoningEffort: chatSettings.openAIReasoningEffort,
|
||||
},
|
||||
mode: PlanActMode.ACT,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}}
|
||||
title={chatSettings.mode === "plan" ? "Click to toggle to Act Mode" : "Already in Act Mode"}
|
||||
title={mode === "plan" ? "Click to toggle to Act Mode" : "Already in Act Mode"}
|
||||
className={`text-[var(--vscode-textLink-foreground)] inline-flex items-center gap-1 ${
|
||||
chatSettings.mode === "plan" ? "hover:opacity-90 cursor-pointer" : "cursor-default opacity-60"
|
||||
mode === "plan" ? "hover:opacity-90 cursor-pointer" : "cursor-default opacity-60"
|
||||
}`}>
|
||||
<div className="p-1 rounded-[12px] bg-[var(--vscode-editor-background)] flex items-center justify-end w-4 border-[1px] border-[var(--vscode-input-border)]">
|
||||
<div className="rounded-full bg-[var(--vscode-textLink-foreground)] w-2 h-2" />
|
||||
|
||||
@@ -37,7 +37,7 @@ import { VSCodeLmProvider } from "./providers/VSCodeLmProvider"
|
||||
import { LMStudioProvider } from "./providers/LMStudioProvider"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { GroqProvider } from "./providers/GroqProvider"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { HuaweiCloudMaasProvider } from "./providers/HuaweiCloudMaasProvider"
|
||||
|
||||
interface ApiOptionsProps {
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import { EmptyRequest } from "@shared/proto/cline/common"
|
||||
import { VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import Fuse from "fuse.js"
|
||||
import React, { KeyboardEvent, memo, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useRemark } from "react-remark"
|
||||
import React, { KeyboardEvent, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useMount } from "react-use"
|
||||
import { groqDefaultModelId, groqModels } from "@shared/api"
|
||||
import { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
import { ModelsServiceClient } from "../../services/grpc-client"
|
||||
import { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
|
||||
import { highlight } from "../history/HistoryView"
|
||||
import { ModelInfoView } from "./common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "./utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { getModeSpecificFields } from "./utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
export interface GroqModelPickerProps {
|
||||
isPopup?: boolean
|
||||
|
||||
@@ -4,7 +4,7 @@ import Fuse from "fuse.js"
|
||||
import React, { KeyboardEvent, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useMount } from "react-use"
|
||||
import { huggingFaceDefaultModelId, huggingFaceModels } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
import { ModelsServiceClient } from "../../services/grpc-client"
|
||||
import { highlight } from "../history/HistoryView"
|
||||
|
||||
@@ -15,7 +15,7 @@ import { getModeSpecificFields, normalizeApiConfiguration } from "./utils/provid
|
||||
import FeaturedModelCard from "./FeaturedModelCard"
|
||||
import ThinkingBudgetSlider from "./ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
// Star icon for favorites
|
||||
const StarIcon = ({ isFavorite, onClick }: { isFavorite: boolean; onClick: (e: React.MouseEvent) => void }) => {
|
||||
|
||||
@@ -2,21 +2,12 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import React from "react"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { updateSetting } from "./utils/settingsHandlers"
|
||||
import { convertChatSettingsToProtoChatSettings } from "@shared/proto-conversions/state/chat-settings-conversion"
|
||||
|
||||
const PreferredLanguageSetting: React.FC = () => {
|
||||
const { chatSettings } = useExtensionState()
|
||||
const { preferredLanguage } = useExtensionState()
|
||||
|
||||
const handleLanguageChange = (newLanguage: string) => {
|
||||
if (!chatSettings) return
|
||||
|
||||
const updatedChatSettings = {
|
||||
...chatSettings,
|
||||
preferredLanguage: newLanguage,
|
||||
}
|
||||
|
||||
const protoChatSettings = convertChatSettingsToProtoChatSettings(updatedChatSettings)
|
||||
updateSetting("chatSettings", protoChatSettings)
|
||||
updateSetting("preferredLanguage", newLanguage)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -26,7 +17,7 @@ const PreferredLanguageSetting: React.FC = () => {
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
id="preferred-language-dropdown"
|
||||
currentValue={chatSettings.preferredLanguage || "English"}
|
||||
currentValue={preferredLanguage || "English"}
|
||||
onChange={(e: any) => {
|
||||
handleLanguageChange(e.target.value)
|
||||
}}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ModelInfoView } from "./common/ModelInfoView"
|
||||
import { getModeSpecificFields, normalizeApiConfiguration } from "./utils/providerUtils"
|
||||
import ThinkingBudgetSlider from "./ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
export interface RequestyModelPickerProps {
|
||||
isPopup?: boolean
|
||||
|
||||
@@ -2,7 +2,7 @@ import HeroTooltip from "@/components/common/HeroTooltip"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { StateServiceClient } from "@/services/grpc-client"
|
||||
import { ExtensionMessage } from "@shared/ExtensionMessage"
|
||||
import { PlanActMode, ResetStateRequest, TogglePlanActModeRequest } from "@shared/proto/cline/state"
|
||||
import { ResetStateRequest } from "@shared/proto/cline/state"
|
||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
import { CheckCheck, FlaskConical, Info, LucideIcon, Settings, SquareMousePointer, SquareTerminal, Webhook } from "lucide-react"
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
@@ -104,7 +104,7 @@ const SettingsView = ({ onDone, targetSection }: SettingsViewProps) => {
|
||||
const [activeTab, setActiveTab] = useState<string>(targetSection || SETTINGS_TABS[0].id)
|
||||
// Track if we're currently switching modes
|
||||
|
||||
const { version, chatSettings } = useExtensionState()
|
||||
const { version } = useExtensionState()
|
||||
|
||||
const handleMessage = useCallback((event: MessageEvent) => {
|
||||
const message: ExtensionMessage = event.data
|
||||
|
||||
@@ -5,7 +5,7 @@ import styled from "styled-components"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { getModeSpecificFields } from "./utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
// Constants
|
||||
const DEFAULT_MIN_VALID_TOKENS = 1024
|
||||
|
||||
@@ -7,7 +7,7 @@ import { getModeSpecificFields, normalizeApiConfiguration } from "../utils/provi
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
// Anthropic models that support thinking/reasoning mode
|
||||
export const SUPPORTED_ANTHROPIC_THINKING_MODELS = [
|
||||
|
||||
@@ -6,8 +6,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the AskSageProvider component
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,7 @@ import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
// Z-index constants for proper dropdown layering
|
||||
const DROPDOWN_Z_INDEX = 1000
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the CerebrasProvider component
|
||||
*/
|
||||
|
||||
@@ -7,8 +7,7 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { SUPPORTED_ANTHROPIC_THINKING_MODELS } from "./AnthropicProvider"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the ClaudeCodeProvider component
|
||||
*/
|
||||
|
||||
@@ -6,8 +6,7 @@ import OpenRouterModelPicker, { OPENROUTER_MODEL_PICKER_Z_INDEX } from "../OpenR
|
||||
import { DropdownContainer } from "../common/ModelSelector"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the ClineProvider component
|
||||
*/
|
||||
|
||||
@@ -5,8 +5,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the DeepSeekProvider component
|
||||
*/
|
||||
|
||||
@@ -5,8 +5,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the DoubaoProvider component
|
||||
*/
|
||||
|
||||
@@ -4,8 +4,7 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the FireworksProvider component
|
||||
*/
|
||||
|
||||
@@ -7,8 +7,7 @@ import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
// Gemini models that support thinking/reasoning mode
|
||||
const SUPPORTED_THINKING_MODELS = ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite-preview-06-17"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import GroqModelPicker from "../GroqModelPicker"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { huaweiCloudMaasModels } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { ModelSelector } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { huggingFaceModels } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { ModelSelector } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
|
||||
@@ -8,8 +8,7 @@ import { BaseUrlField } from "../common/BaseUrlField"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the LMStudioProvider component
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the LiteLlmProvider component
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { ApiConfiguration, mistralModels } from "@shared/api"
|
||||
import { mistralModels } from "@shared/api"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { ModelSelector } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the MistralProvider component
|
||||
*/
|
||||
|
||||
@@ -7,8 +7,7 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useState } from "react"
|
||||
import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the MoonshotProvider component
|
||||
*/
|
||||
|
||||
@@ -5,8 +5,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the NebiusProvider component
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,7 @@ import { BaseUrlField } from "../common/BaseUrlField"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the OllamaProvider component
|
||||
*/
|
||||
|
||||
@@ -11,8 +11,7 @@ import { BaseUrlField } from "../common/BaseUrlField"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the OpenAICompatibleProvider component
|
||||
*/
|
||||
|
||||
@@ -5,8 +5,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the OpenAINativeProvider component
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { VSCodeCheckbox, VSCodeDropdown, VSCodeOption, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { DropdownContainer } from "../common/ModelSelector"
|
||||
@@ -10,8 +9,7 @@ import OpenRouterModelPicker, { OPENROUTER_MODEL_PICKER_Z_INDEX } from "../OpenR
|
||||
import { formatPrice } from "../utils/pricingUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Component to display OpenRouter balance information
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@ import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { DROPDOWN_Z_INDEX } from "../ApiOptions"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { useMemo } from "react"
|
||||
|
||||
const SUPPORTED_THINKING_MODELS = [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import RequestyModelPicker from "../RequestyModelPicker"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
|
||||
@@ -5,8 +5,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the SambanovaProvider component
|
||||
*/
|
||||
|
||||
@@ -6,8 +6,7 @@ import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the SapAiCoreProvider component
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the TogetherProvider component
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,7 @@ import { DropdownContainer, DROPDOWN_Z_INDEX } from "../ApiOptions"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
interface VSCodeLmProviderProps {
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import { DropdownContainer, DROPDOWN_Z_INDEX } from "../ApiOptions"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the VertexProvider component
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { xaiModels } from "@shared/api"
|
||||
import { VSCodeCheckbox, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useState, useEffect } from "react"
|
||||
import { useState } from "react"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { ModelSelector, DropdownContainer } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
@@ -8,8 +8,7 @@ import { getModeSpecificFields, normalizeApiConfiguration } from "../utils/provi
|
||||
import { DROPDOWN_Z_INDEX } from "../ApiOptions"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
/**
|
||||
* Props for the XaiProvider component
|
||||
*/
|
||||
|
||||
@@ -8,15 +8,14 @@ import { UpdateSettingsRequest } from "@shared/proto/cline/state"
|
||||
import { useState } from "react"
|
||||
import { syncModeConfigurations } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
import { Mode } from "@shared/storage/types"
|
||||
interface ApiConfigurationSectionProps {
|
||||
renderSectionHeader: (tabId: string) => JSX.Element | null
|
||||
}
|
||||
|
||||
const ApiConfigurationSection = ({ renderSectionHeader }: ApiConfigurationSectionProps) => {
|
||||
const { planActSeparateModelsSetting, chatSettings, apiConfiguration } = useExtensionState()
|
||||
const [currentTab, setCurrentTab] = useState<Mode>(chatSettings.mode)
|
||||
const { planActSeparateModelsSetting, mode, apiConfiguration } = useExtensionState()
|
||||
const [currentTab, setCurrentTab] = useState<Mode>(mode)
|
||||
const { handleFieldsChange } = useApiConfigurationHandlers()
|
||||
return (
|
||||
<div>
|
||||
@@ -54,7 +53,7 @@ const ApiConfigurationSection = ({ renderSectionHeader }: ApiConfigurationSectio
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<ApiOptions showModelOptions={true} currentMode={chatSettings.mode} />
|
||||
<ApiOptions showModelOptions={true} currentMode={mode} />
|
||||
)}
|
||||
|
||||
<div className="mb-[5px]">
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { VSCodeCheckbox, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { memo } from "react"
|
||||
import { OpenAIReasoningEffort } from "@shared/ChatSettings"
|
||||
import { OpenaiReasoningEffort } from "@shared/storage/types"
|
||||
import { updateSetting } from "../utils/settingsHandlers"
|
||||
import { convertChatSettingsToProtoChatSettings } from "@shared/proto-conversions/state/chat-settings-conversion"
|
||||
import { McpDisplayMode } from "@shared/McpDisplayMode"
|
||||
import McpDisplayModeDropdown from "@/components/mcp/chat-display/McpDisplayModeDropdown"
|
||||
import Section from "../Section"
|
||||
@@ -13,19 +12,11 @@ interface FeatureSettingsSectionProps {
|
||||
}
|
||||
|
||||
const FeatureSettingsSection = ({ renderSectionHeader }: FeatureSettingsSectionProps) => {
|
||||
const { enableCheckpointsSetting, mcpMarketplaceEnabled, mcpDisplayMode, mcpResponsesCollapsed, chatSettings } =
|
||||
const { enableCheckpointsSetting, mcpMarketplaceEnabled, mcpDisplayMode, mcpResponsesCollapsed, openaiReasoningEffort } =
|
||||
useExtensionState()
|
||||
|
||||
const handleReasoningEffortChange = (newValue: OpenAIReasoningEffort) => {
|
||||
if (!chatSettings) return
|
||||
|
||||
const updatedChatSettings = {
|
||||
...chatSettings,
|
||||
openAIReasoningEffort: newValue,
|
||||
}
|
||||
|
||||
const protoChatSettings = convertChatSettingsToProtoChatSettings(updatedChatSettings)
|
||||
updateSetting("chatSettings", protoChatSettings)
|
||||
const handleReasoningEffortChange = (newValue: OpenaiReasoningEffort) => {
|
||||
updateSetting("openaiReasoningEffort", newValue)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -98,9 +89,9 @@ const FeatureSettingsSection = ({ renderSectionHeader }: FeatureSettingsSectionP
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
id="openai-reasoning-effort-dropdown"
|
||||
currentValue={chatSettings.openAIReasoningEffort || "medium"}
|
||||
currentValue={openaiReasoningEffort || "medium"}
|
||||
onChange={(e: any) => {
|
||||
const newValue = e.target.currentValue as OpenAIReasoningEffort
|
||||
const newValue = e.target.currentValue as OpenaiReasoningEffort
|
||||
handleReasoningEffortChange(newValue)
|
||||
}}
|
||||
className="w-full">
|
||||
|
||||
@@ -51,7 +51,7 @@ import {
|
||||
huaweiCloudMaasModels,
|
||||
huaweiCloudMaasDefaultModelId,
|
||||
} from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
/**
|
||||
* Interface for normalized API configuration
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { ModelsServiceClient } from "@/services/grpc-client"
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import { convertApiConfigurationToProto } from "@shared/proto-conversions/models/api-configuration-conversion"
|
||||
import { UpdateApiConfigurationRequest } from "@shared/proto/cline/models"
|
||||
import { useCallback } from "react"
|
||||
|
||||
export const useApiConfigurationHandlers = () => {
|
||||
const { apiConfiguration, planActSeparateModelsSetting } = useExtensionState()
|
||||
|
||||
@@ -8,7 +8,7 @@ import { AccountServiceClient, StateServiceClient } from "@/services/grpc-client
|
||||
import { EmptyRequest, BooleanRequest } from "@shared/proto/cline/common"
|
||||
|
||||
const WelcomeView = memo(() => {
|
||||
const { apiConfiguration, chatSettings } = useExtensionState()
|
||||
const { apiConfiguration, mode } = useExtensionState()
|
||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
||||
const [showApiOptions, setShowApiOptions] = useState(false)
|
||||
|
||||
@@ -29,8 +29,8 @@ const WelcomeView = memo(() => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setApiErrorMessage(validateApiConfiguration(chatSettings.mode, apiConfiguration))
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
setApiErrorMessage(validateApiConfiguration(mode, apiConfiguration))
|
||||
}, [apiConfiguration, mode])
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 p-0 flex flex-col">
|
||||
@@ -70,7 +70,7 @@ const WelcomeView = memo(() => {
|
||||
<div className="mt-4.5">
|
||||
{showApiOptions && (
|
||||
<div>
|
||||
<ApiOptions showModelOptions={false} currentMode={chatSettings.mode} />
|
||||
<ApiOptions showModelOptions={false} currentMode={mode} />
|
||||
<VSCodeButton onClick={handleSubmit} disabled={disableLetsGoButton} className="mt-0.75">
|
||||
Let's go!
|
||||
</VSCodeButton>
|
||||
|
||||
@@ -4,7 +4,6 @@ import "../../../src/shared/webview/types"
|
||||
import { DEFAULT_AUTO_APPROVAL_SETTINGS } from "@shared/AutoApprovalSettings"
|
||||
import { findLastIndex } from "@shared/array"
|
||||
import { DEFAULT_BROWSER_SETTINGS } from "@shared/BrowserSettings"
|
||||
import { type ChatSettings, DEFAULT_CHAT_SETTINGS } from "@shared/ChatSettings"
|
||||
import { DEFAULT_PLATFORM, type ExtensionState } from "@shared/ExtensionMessage"
|
||||
import { DEFAULT_MCP_DISPLAY_MODE } from "@shared/McpDisplayMode"
|
||||
import type { UserInfo } from "@shared/proto/cline/account"
|
||||
@@ -59,7 +58,6 @@ interface ExtensionStateContextType extends ExtensionState {
|
||||
// Setters
|
||||
setShowAnnouncement: (value: boolean) => void
|
||||
setShouldShowAnnouncement: (value: boolean) => void
|
||||
setChatSettings: (value: ChatSettings) => void
|
||||
setMcpServers: (value: McpServer[]) => void
|
||||
setRequestyModels: (value: Record<string, ModelInfo>) => void
|
||||
setGroqModels: (value: Record<string, ModelInfo>) => void
|
||||
@@ -176,7 +174,9 @@ export const ExtensionStateContextProvider: React.FC<{
|
||||
shouldShowAnnouncement: false,
|
||||
autoApprovalSettings: DEFAULT_AUTO_APPROVAL_SETTINGS,
|
||||
browserSettings: DEFAULT_BROWSER_SETTINGS,
|
||||
chatSettings: DEFAULT_CHAT_SETTINGS,
|
||||
preferredLanguage: "English",
|
||||
openaiReasoningEffort: "medium",
|
||||
mode: "act",
|
||||
platform: DEFAULT_PLATFORM,
|
||||
telemetrySetting: "unset",
|
||||
distinctId: "",
|
||||
@@ -686,38 +686,6 @@ export const ExtensionStateContextProvider: React.FC<{
|
||||
setMcpMarketplaceCatalog: (catalog: McpMarketplaceCatalog) => setMcpMarketplaceCatalog(catalog),
|
||||
setShowMcp,
|
||||
closeMcpView,
|
||||
setChatSettings: async (value) => {
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
chatSettings: value,
|
||||
}))
|
||||
try {
|
||||
// Import the conversion functions
|
||||
const { convertApiConfigurationToProtoApiConfiguration } = await import(
|
||||
"@shared/proto-conversions/state/settings-conversion"
|
||||
)
|
||||
const { convertChatSettingsToProtoChatSettings } = await import(
|
||||
"@shared/proto-conversions/state/chat-settings-conversion"
|
||||
)
|
||||
|
||||
await StateServiceClient.updateSettings(
|
||||
UpdateSettingsRequest.create({
|
||||
chatSettings: convertChatSettingsToProtoChatSettings(value),
|
||||
apiConfiguration: state.apiConfiguration
|
||||
? convertApiConfigurationToProtoApiConfiguration(state.apiConfiguration)
|
||||
: undefined,
|
||||
telemetrySetting: state.telemetrySetting,
|
||||
planActSeparateModelsSetting: state.planActSeparateModelsSetting,
|
||||
enableCheckpointsSetting: state.enableCheckpointsSetting,
|
||||
mcpMarketplaceEnabled: state.mcpMarketplaceEnabled,
|
||||
mcpDisplayMode: state.mcpDisplayMode,
|
||||
mcpResponsesCollapsed: state.mcpResponsesCollapsed,
|
||||
}),
|
||||
)
|
||||
} catch (error) {
|
||||
console.error("Failed to update chat settings:", error)
|
||||
}
|
||||
},
|
||||
setGlobalClineRulesToggles: (toggles) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ApiConfiguration, openRouterDefaultModelId, ModelInfo } from "@shared/api"
|
||||
import { getModeSpecificFields } from "@/components/settings/utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
|
||||
export function validateApiConfiguration(currentMode: Mode, apiConfiguration?: ApiConfiguration): string | undefined {
|
||||
if (apiConfiguration) {
|
||||
|
||||
Reference in New Issue
Block a user