|
|
@@ -7,17 +7,18 @@ import pWaitFor from "p-wait-for"
|
|
|
import * as path from "path"
|
|
|
import * as vscode from "vscode"
|
|
|
import simpleGit from "simple-git"
|
|
|
+import { setPanel } from "../../activate/registerCommands"
|
|
|
|
|
|
-import { ApiConfiguration, ApiProvider, ModelInfo } from "../../shared/api"
|
|
|
+import { ApiConfiguration, ApiProvider, ModelInfo, API_CONFIG_KEYS } from "../../shared/api"
|
|
|
import { CheckpointStorage } from "../../shared/checkpoints"
|
|
|
import { findLast } from "../../shared/array"
|
|
|
import { CustomSupportPrompts, supportPrompt } from "../../shared/support-prompt"
|
|
|
import { GlobalFileNames } from "../../shared/globalFileNames"
|
|
|
-import type { SecretKey, GlobalStateKey } from "../../shared/globalState"
|
|
|
+import { SecretKey, GlobalStateKey, SECRET_KEYS, GLOBAL_STATE_KEYS } from "../../shared/globalState"
|
|
|
import { HistoryItem } from "../../shared/HistoryItem"
|
|
|
import { ApiConfigMeta, ExtensionMessage } from "../../shared/ExtensionMessage"
|
|
|
import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage"
|
|
|
-import { Mode, CustomModePrompts, PromptComponent, defaultModeSlug } from "../../shared/modes"
|
|
|
+import { Mode, CustomModePrompts, PromptComponent, defaultModeSlug, ModeConfig } from "../../shared/modes"
|
|
|
import { checkExistKey } from "../../shared/checkExistApiConfig"
|
|
|
import { EXPERIMENT_IDS, experiments as Experiments, experimentDefault, ExperimentId } from "../../shared/experiments"
|
|
|
import { downloadTask } from "../../integrations/misc/export-markdown"
|
|
|
@@ -35,6 +36,7 @@ import { getDiffStrategy } from "../diff/DiffStrategy"
|
|
|
import { SYSTEM_PROMPT } from "../prompts/system"
|
|
|
import { ConfigManager } from "../config/ConfigManager"
|
|
|
import { CustomModesManager } from "../config/CustomModesManager"
|
|
|
+import { ContextProxy } from "../contextProxy"
|
|
|
import { buildApiHandler } from "../../api"
|
|
|
import { getOpenRouterModels } from "../../api/providers/openrouter"
|
|
|
import { getGlamaModels } from "../../api/providers/glama"
|
|
|
@@ -66,6 +68,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
private workspaceTracker?: WorkspaceTracker
|
|
|
protected mcpHub?: McpHub // Change from private to protected
|
|
|
private latestAnnouncementId = "feb-27-2025-automatic-checkpoints" // update to some unique identifier when we add a new announcement
|
|
|
+ private contextProxy: ContextProxy
|
|
|
configManager: ConfigManager
|
|
|
customModesManager: CustomModesManager
|
|
|
private lastTaskNumber = -1
|
|
|
@@ -75,6 +78,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
private readonly outputChannel: vscode.OutputChannel,
|
|
|
) {
|
|
|
this.outputChannel.appendLine("ClineProvider instantiated")
|
|
|
+ this.contextProxy = new ContextProxy(context)
|
|
|
ClineProvider.activeInstances.add(this)
|
|
|
this.workspaceTracker = new WorkspaceTracker(this)
|
|
|
this.configManager = new ConfigManager(this.context)
|
|
|
@@ -376,6 +380,15 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
this.outputChannel.appendLine("Resolving webview view")
|
|
|
this.view = webviewView
|
|
|
|
|
|
+ // Set panel reference according to webview type
|
|
|
+ if ("onDidChangeViewState" in webviewView) {
|
|
|
+ // Tag page type
|
|
|
+ setPanel(webviewView, "tab")
|
|
|
+ } else if ("onDidChangeVisibility" in webviewView) {
|
|
|
+ // Sidebar Type
|
|
|
+ setPanel(webviewView, "sidebar")
|
|
|
+ }
|
|
|
+
|
|
|
// Initialize sound enabled state
|
|
|
this.getState().then(({ soundEnabled }) => {
|
|
|
setSoundEnabled(soundEnabled ?? false)
|
|
|
@@ -384,11 +397,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
webviewView.webview.options = {
|
|
|
// Allow scripts in the webview
|
|
|
enableScripts: true,
|
|
|
- localResourceRoots: [this.context.extensionUri],
|
|
|
+ localResourceRoots: [this.contextProxy.extensionUri],
|
|
|
}
|
|
|
|
|
|
webviewView.webview.html =
|
|
|
- this.context.extensionMode === vscode.ExtensionMode.Development
|
|
|
+ this.contextProxy.extensionMode === vscode.ExtensionMode.Development
|
|
|
? await this.getHMRHtmlContent(webviewView.webview)
|
|
|
: this.getHtmlContent(webviewView.webview)
|
|
|
|
|
|
@@ -552,8 +565,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
|
|
|
const nonce = getNonce()
|
|
|
- const stylesUri = getUri(webview, this.context.extensionUri, ["webview-ui", "build", "assets", "index.css"])
|
|
|
- const codiconsUri = getUri(webview, this.context.extensionUri, [
|
|
|
+ const stylesUri = getUri(webview, this.contextProxy.extensionUri, [
|
|
|
+ "webview-ui",
|
|
|
+ "build",
|
|
|
+ "assets",
|
|
|
+ "index.css",
|
|
|
+ ])
|
|
|
+ const codiconsUri = getUri(webview, this.contextProxy.extensionUri, [
|
|
|
"node_modules",
|
|
|
"@vscode",
|
|
|
"codicons",
|
|
|
@@ -619,15 +637,20 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
// then convert it to a uri we can use in the webview.
|
|
|
|
|
|
// The CSS file from the React build output
|
|
|
- const stylesUri = getUri(webview, this.context.extensionUri, ["webview-ui", "build", "assets", "index.css"])
|
|
|
+ const stylesUri = getUri(webview, this.contextProxy.extensionUri, [
|
|
|
+ "webview-ui",
|
|
|
+ "build",
|
|
|
+ "assets",
|
|
|
+ "index.css",
|
|
|
+ ])
|
|
|
// The JS file from the React build output
|
|
|
- const scriptUri = getUri(webview, this.context.extensionUri, ["webview-ui", "build", "assets", "index.js"])
|
|
|
+ const scriptUri = getUri(webview, this.contextProxy.extensionUri, ["webview-ui", "build", "assets", "index.js"])
|
|
|
|
|
|
// The codicon font from the React build output
|
|
|
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-codicons-sample/src/extension.ts
|
|
|
// we installed this package in the extension so that we can access it how its intended from the extension (the font file is likely bundled in vscode), and we just import the css fileinto our react app we don't have access to it
|
|
|
// don't forget to add font-src ${webview.cspSource};
|
|
|
- const codiconsUri = getUri(webview, this.context.extensionUri, [
|
|
|
+ const codiconsUri = getUri(webview, this.contextProxy.extensionUri, [
|
|
|
"node_modules",
|
|
|
"@vscode",
|
|
|
"codicons",
|
|
|
@@ -1431,7 +1454,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
// Try to get enhancement config first, fall back to current config
|
|
|
let configToUse: ApiConfiguration = apiConfiguration
|
|
|
if (enhancementApiConfigId) {
|
|
|
- const config = listApiConfigMeta?.find((c) => c.id === enhancementApiConfigId)
|
|
|
+ const config = listApiConfigMeta?.find(
|
|
|
+ (c: ApiConfigMeta) => c.id === enhancementApiConfigId,
|
|
|
+ )
|
|
|
if (config?.name) {
|
|
|
const loadedConfig = await this.configManager.loadConfig(config.name)
|
|
|
if (loadedConfig.apiProvider) {
|
|
|
@@ -1709,6 +1734,25 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
await this.updateGlobalState("mode", defaultModeSlug)
|
|
|
await this.postStateToWebview()
|
|
|
}
|
|
|
+ break
|
|
|
+ case "humanRelayResponse":
|
|
|
+ if (message.requestId && message.text) {
|
|
|
+ vscode.commands.executeCommand("roo-cline.handleHumanRelayResponse", {
|
|
|
+ requestId: message.requestId,
|
|
|
+ text: message.text,
|
|
|
+ cancelled: false,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break
|
|
|
+
|
|
|
+ case "humanRelayCancel":
|
|
|
+ if (message.requestId) {
|
|
|
+ vscode.commands.executeCommand("roo-cline.handleHumanRelayResponse", {
|
|
|
+ requestId: message.requestId,
|
|
|
+ cancelled: true,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break
|
|
|
}
|
|
|
},
|
|
|
null,
|
|
|
@@ -1810,108 +1854,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const {
|
|
|
- apiProvider,
|
|
|
- apiModelId,
|
|
|
- apiKey,
|
|
|
- glamaModelId,
|
|
|
- glamaModelInfo,
|
|
|
- glamaApiKey,
|
|
|
- openRouterApiKey,
|
|
|
- awsAccessKey,
|
|
|
- awsSecretKey,
|
|
|
- awsSessionToken,
|
|
|
- awsRegion,
|
|
|
- awsUseCrossRegionInference,
|
|
|
- awsProfile,
|
|
|
- awsUseProfile,
|
|
|
- vertexProjectId,
|
|
|
- vertexRegion,
|
|
|
- openAiBaseUrl,
|
|
|
- openAiApiKey,
|
|
|
- openAiModelId,
|
|
|
- openAiCustomModelInfo,
|
|
|
- openAiUseAzure,
|
|
|
- ollamaModelId,
|
|
|
- ollamaBaseUrl,
|
|
|
- lmStudioModelId,
|
|
|
- lmStudioBaseUrl,
|
|
|
- anthropicBaseUrl,
|
|
|
- geminiApiKey,
|
|
|
- openAiNativeApiKey,
|
|
|
- deepSeekApiKey,
|
|
|
- azureApiVersion,
|
|
|
- openAiStreamingEnabled,
|
|
|
- openRouterModelId,
|
|
|
- openRouterBaseUrl,
|
|
|
- openRouterModelInfo,
|
|
|
- openRouterUseMiddleOutTransform,
|
|
|
- vsCodeLmModelSelector,
|
|
|
- mistralApiKey,
|
|
|
- mistralCodestralUrl,
|
|
|
- unboundApiKey,
|
|
|
- unboundModelId,
|
|
|
- unboundModelInfo,
|
|
|
- requestyApiKey,
|
|
|
- requestyModelId,
|
|
|
- requestyModelInfo,
|
|
|
- modelTemperature,
|
|
|
- modelMaxTokens,
|
|
|
- modelMaxThinkingTokens,
|
|
|
- lmStudioDraftModelId,
|
|
|
- lmStudioSpeculativeDecodingEnabled,
|
|
|
- } = apiConfiguration
|
|
|
- await Promise.all([
|
|
|
- this.updateGlobalState("apiProvider", apiProvider),
|
|
|
- this.updateGlobalState("apiModelId", apiModelId),
|
|
|
- this.storeSecret("apiKey", apiKey),
|
|
|
- this.updateGlobalState("glamaModelId", glamaModelId),
|
|
|
- this.updateGlobalState("glamaModelInfo", glamaModelInfo),
|
|
|
- this.storeSecret("glamaApiKey", glamaApiKey),
|
|
|
- this.storeSecret("openRouterApiKey", openRouterApiKey),
|
|
|
- this.storeSecret("awsAccessKey", awsAccessKey),
|
|
|
- this.storeSecret("awsSecretKey", awsSecretKey),
|
|
|
- this.storeSecret("awsSessionToken", awsSessionToken),
|
|
|
- this.updateGlobalState("awsRegion", awsRegion),
|
|
|
- this.updateGlobalState("awsUseCrossRegionInference", awsUseCrossRegionInference),
|
|
|
- this.updateGlobalState("awsProfile", awsProfile),
|
|
|
- this.updateGlobalState("awsUseProfile", awsUseProfile),
|
|
|
- this.updateGlobalState("vertexProjectId", vertexProjectId),
|
|
|
- this.updateGlobalState("vertexRegion", vertexRegion),
|
|
|
- this.updateGlobalState("openAiBaseUrl", openAiBaseUrl),
|
|
|
- this.storeSecret("openAiApiKey", openAiApiKey),
|
|
|
- this.updateGlobalState("openAiModelId", openAiModelId),
|
|
|
- this.updateGlobalState("openAiCustomModelInfo", openAiCustomModelInfo),
|
|
|
- this.updateGlobalState("openAiUseAzure", openAiUseAzure),
|
|
|
- this.updateGlobalState("ollamaModelId", ollamaModelId),
|
|
|
- this.updateGlobalState("ollamaBaseUrl", ollamaBaseUrl),
|
|
|
- this.updateGlobalState("lmStudioModelId", lmStudioModelId),
|
|
|
- this.updateGlobalState("lmStudioBaseUrl", lmStudioBaseUrl),
|
|
|
- this.updateGlobalState("anthropicBaseUrl", anthropicBaseUrl),
|
|
|
- this.storeSecret("geminiApiKey", geminiApiKey),
|
|
|
- this.storeSecret("openAiNativeApiKey", openAiNativeApiKey),
|
|
|
- this.storeSecret("deepSeekApiKey", deepSeekApiKey),
|
|
|
- this.updateGlobalState("azureApiVersion", azureApiVersion),
|
|
|
- this.updateGlobalState("openAiStreamingEnabled", openAiStreamingEnabled),
|
|
|
- this.updateGlobalState("openRouterModelId", openRouterModelId),
|
|
|
- this.updateGlobalState("openRouterModelInfo", openRouterModelInfo),
|
|
|
- this.updateGlobalState("openRouterBaseUrl", openRouterBaseUrl),
|
|
|
- this.updateGlobalState("openRouterUseMiddleOutTransform", openRouterUseMiddleOutTransform),
|
|
|
- this.updateGlobalState("vsCodeLmModelSelector", vsCodeLmModelSelector),
|
|
|
- this.storeSecret("mistralApiKey", mistralApiKey),
|
|
|
- this.updateGlobalState("mistralCodestralUrl", mistralCodestralUrl),
|
|
|
- this.storeSecret("unboundApiKey", unboundApiKey),
|
|
|
- this.updateGlobalState("unboundModelId", unboundModelId),
|
|
|
- this.updateGlobalState("unboundModelInfo", unboundModelInfo),
|
|
|
- this.storeSecret("requestyApiKey", requestyApiKey),
|
|
|
- this.updateGlobalState("requestyModelId", requestyModelId),
|
|
|
- this.updateGlobalState("requestyModelInfo", requestyModelInfo),
|
|
|
- this.updateGlobalState("modelTemperature", modelTemperature),
|
|
|
- this.updateGlobalState("modelMaxTokens", modelMaxTokens),
|
|
|
- this.updateGlobalState("anthropicThinking", modelMaxThinkingTokens),
|
|
|
- this.updateGlobalState("lmStudioDraftModelId", lmStudioDraftModelId),
|
|
|
- this.updateGlobalState("lmStudioSpeculativeDecodingEnabled", lmStudioSpeculativeDecodingEnabled),
|
|
|
- ])
|
|
|
+ // Use the new setValues method to handle routing values to secrets or global state
|
|
|
+ await this.contextProxy.setValues(apiConfiguration)
|
|
|
+
|
|
|
if (this.getCurrentCline()) {
|
|
|
this.getCurrentCline()!.api = buildApiHandler(apiConfiguration)
|
|
|
}
|
|
|
@@ -1972,13 +1917,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
|
|
|
async ensureSettingsDirectoryExists(): Promise<string> {
|
|
|
- const settingsDir = path.join(this.context.globalStorageUri.fsPath, "settings")
|
|
|
+ const settingsDir = path.join(this.contextProxy.globalStorageUri.fsPath, "settings")
|
|
|
await fs.mkdir(settingsDir, { recursive: true })
|
|
|
return settingsDir
|
|
|
}
|
|
|
|
|
|
private async ensureCacheDirectoryExists() {
|
|
|
- const cacheDir = path.join(this.context.globalStorageUri.fsPath, "cache")
|
|
|
+ const cacheDir = path.join(this.contextProxy.globalStorageUri.fsPath, "cache")
|
|
|
await fs.mkdir(cacheDir, { recursive: true })
|
|
|
return cacheDir
|
|
|
}
|
|
|
@@ -2014,8 +1959,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
|
|
|
const openrouter: ApiProvider = "openrouter"
|
|
|
- await this.updateGlobalState("apiProvider", openrouter)
|
|
|
- await this.storeSecret("openRouterApiKey", apiKey)
|
|
|
+ await this.contextProxy.setValues({
|
|
|
+ apiProvider: openrouter,
|
|
|
+ openRouterApiKey: apiKey,
|
|
|
+ })
|
|
|
+
|
|
|
await this.postStateToWebview()
|
|
|
if (this.getCurrentCline()) {
|
|
|
this.getCurrentCline()!.api = buildApiHandler({ apiProvider: openrouter, openRouterApiKey: apiKey })
|
|
|
@@ -2042,8 +1990,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
|
|
|
const glama: ApiProvider = "glama"
|
|
|
- await this.updateGlobalState("apiProvider", glama)
|
|
|
- await this.storeSecret("glamaApiKey", apiKey)
|
|
|
+ await this.contextProxy.setValues({
|
|
|
+ apiProvider: glama,
|
|
|
+ glamaApiKey: apiKey,
|
|
|
+ })
|
|
|
await this.postStateToWebview()
|
|
|
if (this.getCurrentCline()) {
|
|
|
this.getCurrentCline()!.api = buildApiHandler({
|
|
|
@@ -2066,7 +2016,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
const history = ((await this.getGlobalState("taskHistory")) as HistoryItem[] | undefined) || []
|
|
|
const historyItem = history.find((item) => item.id === id)
|
|
|
if (historyItem) {
|
|
|
- const taskDirPath = path.join(this.context.globalStorageUri.fsPath, "tasks", id)
|
|
|
+ const taskDirPath = path.join(this.contextProxy.globalStorageUri.fsPath, "tasks", id)
|
|
|
const apiConversationHistoryFilePath = path.join(taskDirPath, GlobalFileNames.apiConversationHistory)
|
|
|
const uiMessagesFilePath = path.join(taskDirPath, GlobalFileNames.uiMessages)
|
|
|
const fileExists = await fileExistsAtPath(apiConversationHistoryFilePath)
|
|
|
@@ -2215,7 +2165,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false,
|
|
|
uriScheme: vscode.env.uriScheme,
|
|
|
currentTaskItem: this.getCurrentCline()?.taskId
|
|
|
- ? (taskHistory || []).find((item) => item.id === this.getCurrentCline()?.taskId)
|
|
|
+ ? (taskHistory || []).find((item: HistoryItem) => item.id === this.getCurrentCline()?.taskId)
|
|
|
: undefined,
|
|
|
clineMessages: this.getCurrentCline()?.clineMessages || [],
|
|
|
taskHistory: (taskHistory || [])
|
|
|
@@ -2302,191 +2252,41 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
*/
|
|
|
|
|
|
async getState() {
|
|
|
- const [
|
|
|
- storedApiProvider,
|
|
|
- apiModelId,
|
|
|
- apiKey,
|
|
|
- glamaApiKey,
|
|
|
- glamaModelId,
|
|
|
- glamaModelInfo,
|
|
|
- openRouterApiKey,
|
|
|
- awsAccessKey,
|
|
|
- awsSecretKey,
|
|
|
- awsSessionToken,
|
|
|
- awsRegion,
|
|
|
- awsUseCrossRegionInference,
|
|
|
- awsProfile,
|
|
|
- awsUseProfile,
|
|
|
- vertexProjectId,
|
|
|
- vertexRegion,
|
|
|
- openAiBaseUrl,
|
|
|
- openAiApiKey,
|
|
|
- openAiModelId,
|
|
|
- openAiCustomModelInfo,
|
|
|
- openAiUseAzure,
|
|
|
- ollamaModelId,
|
|
|
- ollamaBaseUrl,
|
|
|
- lmStudioModelId,
|
|
|
- lmStudioBaseUrl,
|
|
|
- anthropicBaseUrl,
|
|
|
- geminiApiKey,
|
|
|
- openAiNativeApiKey,
|
|
|
- deepSeekApiKey,
|
|
|
- mistralApiKey,
|
|
|
- mistralCodestralUrl,
|
|
|
- azureApiVersion,
|
|
|
- openAiStreamingEnabled,
|
|
|
- openRouterModelId,
|
|
|
- openRouterModelInfo,
|
|
|
- openRouterBaseUrl,
|
|
|
- openRouterUseMiddleOutTransform,
|
|
|
- lastShownAnnouncementId,
|
|
|
- customInstructions,
|
|
|
- alwaysAllowReadOnly,
|
|
|
- alwaysAllowWrite,
|
|
|
- alwaysAllowExecute,
|
|
|
- alwaysAllowBrowser,
|
|
|
- alwaysAllowMcp,
|
|
|
- alwaysAllowModeSwitch,
|
|
|
- taskHistory,
|
|
|
- allowedCommands,
|
|
|
- soundEnabled,
|
|
|
- diffEnabled,
|
|
|
- enableCheckpoints,
|
|
|
- checkpointStorage,
|
|
|
- soundVolume,
|
|
|
- browserViewportSize,
|
|
|
- fuzzyMatchThreshold,
|
|
|
- preferredLanguage,
|
|
|
- writeDelayMs,
|
|
|
- screenshotQuality,
|
|
|
- terminalOutputLineLimit,
|
|
|
- mcpEnabled,
|
|
|
- enableMcpServerCreation,
|
|
|
- alwaysApproveResubmit,
|
|
|
- requestDelaySeconds,
|
|
|
- rateLimitSeconds,
|
|
|
- currentApiConfigName,
|
|
|
- listApiConfigMeta,
|
|
|
- vsCodeLmModelSelector,
|
|
|
- mode,
|
|
|
- modeApiConfigs,
|
|
|
- customModePrompts,
|
|
|
- customSupportPrompts,
|
|
|
- enhancementApiConfigId,
|
|
|
- autoApprovalEnabled,
|
|
|
- customModes,
|
|
|
- experiments,
|
|
|
- unboundApiKey,
|
|
|
- unboundModelId,
|
|
|
- unboundModelInfo,
|
|
|
- requestyApiKey,
|
|
|
- requestyModelId,
|
|
|
- requestyModelInfo,
|
|
|
- modelTemperature,
|
|
|
- modelMaxTokens,
|
|
|
- modelMaxThinkingTokens,
|
|
|
- maxOpenTabsContext,
|
|
|
- browserToolEnabled,
|
|
|
- lmStudioSpeculativeDecodingEnabled,
|
|
|
- lmStudioDraftModelId,
|
|
|
- ] = await Promise.all([
|
|
|
- this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
|
|
- this.getGlobalState("apiModelId") as Promise<string | undefined>,
|
|
|
- this.getSecret("apiKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("glamaApiKey") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("glamaModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("glamaModelInfo") as Promise<ModelInfo | undefined>,
|
|
|
- this.getSecret("openRouterApiKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("awsAccessKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("awsSecretKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("awsSessionToken") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("awsRegion") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("awsUseCrossRegionInference") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("awsProfile") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("awsUseProfile") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("vertexProjectId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("vertexRegion") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("openAiBaseUrl") as Promise<string | undefined>,
|
|
|
- this.getSecret("openAiApiKey") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("openAiModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("openAiCustomModelInfo") as Promise<ModelInfo | undefined>,
|
|
|
- this.getGlobalState("openAiUseAzure") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("ollamaModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("ollamaBaseUrl") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("lmStudioModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("lmStudioBaseUrl") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("anthropicBaseUrl") as Promise<string | undefined>,
|
|
|
- this.getSecret("geminiApiKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("openAiNativeApiKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("deepSeekApiKey") as Promise<string | undefined>,
|
|
|
- this.getSecret("mistralApiKey") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("mistralCodestralUrl") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("azureApiVersion") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("openAiStreamingEnabled") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("openRouterModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("openRouterModelInfo") as Promise<ModelInfo | undefined>,
|
|
|
- this.getGlobalState("openRouterBaseUrl") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("openRouterUseMiddleOutTransform") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("lastShownAnnouncementId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("customInstructions") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("alwaysAllowReadOnly") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("alwaysAllowWrite") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("alwaysAllowExecute") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("alwaysAllowBrowser") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("alwaysAllowMcp") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("alwaysAllowModeSwitch") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("taskHistory") as Promise<HistoryItem[] | undefined>,
|
|
|
- this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
|
|
|
- this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("diffEnabled") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("enableCheckpoints") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("checkpointStorage") as Promise<CheckpointStorage | undefined>,
|
|
|
- this.getGlobalState("soundVolume") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("browserViewportSize") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("fuzzyMatchThreshold") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("preferredLanguage") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("writeDelayMs") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("screenshotQuality") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("terminalOutputLineLimit") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("mcpEnabled") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("enableMcpServerCreation") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("alwaysApproveResubmit") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("requestDelaySeconds") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("rateLimitSeconds") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("currentApiConfigName") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("listApiConfigMeta") as Promise<ApiConfigMeta[] | undefined>,
|
|
|
- this.getGlobalState("vsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
|
|
- this.getGlobalState("mode") as Promise<Mode | undefined>,
|
|
|
- this.getGlobalState("modeApiConfigs") as Promise<Record<Mode, string> | undefined>,
|
|
|
- this.getGlobalState("customModePrompts") as Promise<CustomModePrompts | undefined>,
|
|
|
- this.getGlobalState("customSupportPrompts") as Promise<CustomSupportPrompts | undefined>,
|
|
|
- this.getGlobalState("enhancementApiConfigId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("autoApprovalEnabled") as Promise<boolean | undefined>,
|
|
|
- this.customModesManager.getCustomModes(),
|
|
|
- this.getGlobalState("experiments") as Promise<Record<ExperimentId, boolean> | undefined>,
|
|
|
- this.getSecret("unboundApiKey") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("unboundModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("unboundModelInfo") as Promise<ModelInfo | undefined>,
|
|
|
- this.getSecret("requestyApiKey") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("requestyModelId") as Promise<string | undefined>,
|
|
|
- this.getGlobalState("requestyModelInfo") as Promise<ModelInfo | undefined>,
|
|
|
- this.getGlobalState("modelTemperature") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("modelMaxTokens") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("anthropicThinking") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("maxOpenTabsContext") as Promise<number | undefined>,
|
|
|
- this.getGlobalState("browserToolEnabled") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("lmStudioSpeculativeDecodingEnabled") as Promise<boolean | undefined>,
|
|
|
- this.getGlobalState("lmStudioDraftModelId") as Promise<string | undefined>,
|
|
|
- ])
|
|
|
+ // Create an object to store all fetched values
|
|
|
+ const stateValues: Record<GlobalStateKey | SecretKey, any> = {} as Record<GlobalStateKey | SecretKey, any>
|
|
|
+ const secretValues: Record<SecretKey, any> = {} as Record<SecretKey, any>
|
|
|
+
|
|
|
+ // Create promise arrays for global state and secrets
|
|
|
+ const statePromises = GLOBAL_STATE_KEYS.map((key) => this.getGlobalState(key))
|
|
|
+ const secretPromises = SECRET_KEYS.map((key) => this.getSecret(key))
|
|
|
+
|
|
|
+ // Add promise for custom modes which is handled separately
|
|
|
+ const customModesPromise = this.customModesManager.getCustomModes()
|
|
|
+
|
|
|
+ let idx = 0
|
|
|
+ const valuePromises = await Promise.all([...statePromises, ...secretPromises, customModesPromise])
|
|
|
+
|
|
|
+ // Populate stateValues and secretValues
|
|
|
+ GLOBAL_STATE_KEYS.forEach((key, _) => {
|
|
|
+ stateValues[key] = valuePromises[idx]
|
|
|
+ idx = idx + 1
|
|
|
+ })
|
|
|
+
|
|
|
+ SECRET_KEYS.forEach((key, index) => {
|
|
|
+ secretValues[key] = valuePromises[idx]
|
|
|
+ idx = idx + 1
|
|
|
+ })
|
|
|
+
|
|
|
+ let customModes = valuePromises[idx] as ModeConfig[] | undefined
|
|
|
|
|
|
+ // Determine apiProvider with the same logic as before
|
|
|
let apiProvider: ApiProvider
|
|
|
- if (storedApiProvider) {
|
|
|
- apiProvider = storedApiProvider
|
|
|
+ if (stateValues.apiProvider) {
|
|
|
+ apiProvider = stateValues.apiProvider
|
|
|
} else {
|
|
|
// Either new user or legacy user that doesn't have the apiProvider stored in state
|
|
|
// (If they're using OpenRouter or Bedrock, then apiProvider state will exist)
|
|
|
- if (apiKey) {
|
|
|
+ if (secretValues.apiKey) {
|
|
|
apiProvider = "anthropic"
|
|
|
} else {
|
|
|
// New users should default to openrouter
|
|
|
@@ -2494,81 +2294,46 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Build the apiConfiguration object combining state values and secrets
|
|
|
+ // Using the dynamic approach with API_CONFIG_KEYS
|
|
|
+ const apiConfiguration: ApiConfiguration = {
|
|
|
+ // Dynamically add all API-related keys from stateValues
|
|
|
+ ...Object.fromEntries(API_CONFIG_KEYS.map((key) => [key, stateValues[key]])),
|
|
|
+ // Add all secrets
|
|
|
+ ...secretValues,
|
|
|
+ }
|
|
|
+
|
|
|
+ // Ensure apiProvider is set properly if not already in state
|
|
|
+ if (!apiConfiguration.apiProvider) {
|
|
|
+ apiConfiguration.apiProvider = apiProvider
|
|
|
+ }
|
|
|
+
|
|
|
+ // Return the same structure as before
|
|
|
return {
|
|
|
- apiConfiguration: {
|
|
|
- apiProvider,
|
|
|
- apiModelId,
|
|
|
- apiKey,
|
|
|
- glamaApiKey,
|
|
|
- glamaModelId,
|
|
|
- glamaModelInfo,
|
|
|
- openRouterApiKey,
|
|
|
- awsAccessKey,
|
|
|
- awsSecretKey,
|
|
|
- awsSessionToken,
|
|
|
- awsRegion,
|
|
|
- awsUseCrossRegionInference,
|
|
|
- awsProfile,
|
|
|
- awsUseProfile,
|
|
|
- vertexProjectId,
|
|
|
- vertexRegion,
|
|
|
- openAiBaseUrl,
|
|
|
- openAiApiKey,
|
|
|
- openAiModelId,
|
|
|
- openAiCustomModelInfo,
|
|
|
- openAiUseAzure,
|
|
|
- ollamaModelId,
|
|
|
- ollamaBaseUrl,
|
|
|
- lmStudioModelId,
|
|
|
- lmStudioBaseUrl,
|
|
|
- anthropicBaseUrl,
|
|
|
- geminiApiKey,
|
|
|
- openAiNativeApiKey,
|
|
|
- deepSeekApiKey,
|
|
|
- mistralApiKey,
|
|
|
- mistralCodestralUrl,
|
|
|
- azureApiVersion,
|
|
|
- openAiStreamingEnabled,
|
|
|
- openRouterModelId,
|
|
|
- openRouterModelInfo,
|
|
|
- openRouterBaseUrl,
|
|
|
- openRouterUseMiddleOutTransform,
|
|
|
- vsCodeLmModelSelector,
|
|
|
- unboundApiKey,
|
|
|
- unboundModelId,
|
|
|
- unboundModelInfo,
|
|
|
- requestyApiKey,
|
|
|
- requestyModelId,
|
|
|
- requestyModelInfo,
|
|
|
- modelTemperature,
|
|
|
- modelMaxTokens,
|
|
|
- modelMaxThinkingTokens,
|
|
|
- lmStudioSpeculativeDecodingEnabled,
|
|
|
- lmStudioDraftModelId,
|
|
|
- },
|
|
|
- lastShownAnnouncementId,
|
|
|
- customInstructions,
|
|
|
- alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
|
|
|
- alwaysAllowWrite: alwaysAllowWrite ?? false,
|
|
|
- alwaysAllowExecute: alwaysAllowExecute ?? false,
|
|
|
- alwaysAllowBrowser: alwaysAllowBrowser ?? false,
|
|
|
- alwaysAllowMcp: alwaysAllowMcp ?? false,
|
|
|
- alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false,
|
|
|
- taskHistory,
|
|
|
- allowedCommands,
|
|
|
- soundEnabled: soundEnabled ?? false,
|
|
|
- diffEnabled: diffEnabled ?? true,
|
|
|
- enableCheckpoints: enableCheckpoints ?? true,
|
|
|
- checkpointStorage: checkpointStorage ?? "task",
|
|
|
- soundVolume,
|
|
|
- browserViewportSize: browserViewportSize ?? "900x600",
|
|
|
- screenshotQuality: screenshotQuality ?? 75,
|
|
|
- fuzzyMatchThreshold: fuzzyMatchThreshold ?? 1.0,
|
|
|
- writeDelayMs: writeDelayMs ?? 1000,
|
|
|
- terminalOutputLineLimit: terminalOutputLineLimit ?? 500,
|
|
|
- mode: mode ?? defaultModeSlug,
|
|
|
+ apiConfiguration,
|
|
|
+ lastShownAnnouncementId: stateValues.lastShownAnnouncementId,
|
|
|
+ customInstructions: stateValues.customInstructions,
|
|
|
+ alwaysAllowReadOnly: stateValues.alwaysAllowReadOnly ?? false,
|
|
|
+ alwaysAllowWrite: stateValues.alwaysAllowWrite ?? false,
|
|
|
+ alwaysAllowExecute: stateValues.alwaysAllowExecute ?? false,
|
|
|
+ alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? false,
|
|
|
+ alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false,
|
|
|
+ alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false,
|
|
|
+ taskHistory: stateValues.taskHistory,
|
|
|
+ allowedCommands: stateValues.allowedCommands,
|
|
|
+ soundEnabled: stateValues.soundEnabled ?? false,
|
|
|
+ diffEnabled: stateValues.diffEnabled ?? true,
|
|
|
+ enableCheckpoints: stateValues.enableCheckpoints ?? false,
|
|
|
+ checkpointStorage: stateValues.checkpointStorage ?? "task",
|
|
|
+ soundVolume: stateValues.soundVolume,
|
|
|
+ browserViewportSize: stateValues.browserViewportSize ?? "900x600",
|
|
|
+ screenshotQuality: stateValues.screenshotQuality ?? 75,
|
|
|
+ fuzzyMatchThreshold: stateValues.fuzzyMatchThreshold ?? 1.0,
|
|
|
+ writeDelayMs: stateValues.writeDelayMs ?? 1000,
|
|
|
+ terminalOutputLineLimit: stateValues.terminalOutputLineLimit ?? 500,
|
|
|
+ mode: stateValues.mode ?? defaultModeSlug,
|
|
|
preferredLanguage:
|
|
|
- preferredLanguage ??
|
|
|
+ stateValues.preferredLanguage ??
|
|
|
(() => {
|
|
|
// Get VSCode's locale setting
|
|
|
const vscodeLang = vscode.env.language
|
|
|
@@ -2598,23 +2363,23 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
// Return mapped language or default to English
|
|
|
return langMap[vscodeLang] ?? langMap[vscodeLang.split("-")[0]] ?? "English"
|
|
|
})(),
|
|
|
- mcpEnabled: mcpEnabled ?? true,
|
|
|
- enableMcpServerCreation: enableMcpServerCreation ?? true,
|
|
|
- alwaysApproveResubmit: alwaysApproveResubmit ?? false,
|
|
|
- requestDelaySeconds: Math.max(5, requestDelaySeconds ?? 10),
|
|
|
- rateLimitSeconds: rateLimitSeconds ?? 0,
|
|
|
- currentApiConfigName: currentApiConfigName ?? "default",
|
|
|
- listApiConfigMeta: listApiConfigMeta ?? [],
|
|
|
- modeApiConfigs: modeApiConfigs ?? ({} as Record<Mode, string>),
|
|
|
- customModePrompts: customModePrompts ?? {},
|
|
|
- customSupportPrompts: customSupportPrompts ?? {},
|
|
|
- enhancementApiConfigId,
|
|
|
- experiments: experiments ?? experimentDefault,
|
|
|
- autoApprovalEnabled: autoApprovalEnabled ?? false,
|
|
|
+ mcpEnabled: stateValues.mcpEnabled ?? true,
|
|
|
+ enableMcpServerCreation: stateValues.enableMcpServerCreation ?? true,
|
|
|
+ alwaysApproveResubmit: stateValues.alwaysApproveResubmit ?? false,
|
|
|
+ requestDelaySeconds: Math.max(5, stateValues.requestDelaySeconds ?? 10),
|
|
|
+ rateLimitSeconds: stateValues.rateLimitSeconds ?? 0,
|
|
|
+ currentApiConfigName: stateValues.currentApiConfigName ?? "default",
|
|
|
+ listApiConfigMeta: stateValues.listApiConfigMeta ?? [],
|
|
|
+ modeApiConfigs: stateValues.modeApiConfigs ?? ({} as Record<Mode, string>),
|
|
|
+ customModePrompts: stateValues.customModePrompts ?? {},
|
|
|
+ customSupportPrompts: stateValues.customSupportPrompts ?? {},
|
|
|
+ enhancementApiConfigId: stateValues.enhancementApiConfigId,
|
|
|
+ experiments: stateValues.experiments ?? experimentDefault,
|
|
|
+ autoApprovalEnabled: stateValues.autoApprovalEnabled ?? false,
|
|
|
customModes,
|
|
|
- maxOpenTabsContext: maxOpenTabsContext ?? 20,
|
|
|
- openRouterUseMiddleOutTransform: openRouterUseMiddleOutTransform ?? true,
|
|
|
- browserToolEnabled: browserToolEnabled ?? true,
|
|
|
+ maxOpenTabsContext: stateValues.maxOpenTabsContext ?? 20,
|
|
|
+ openRouterUseMiddleOutTransform: stateValues.openRouterUseMiddleOutTransform ?? true,
|
|
|
+ browserToolEnabled: stateValues.browserToolEnabled ?? true,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2634,25 +2399,21 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
// global
|
|
|
|
|
|
async updateGlobalState(key: GlobalStateKey, value: any) {
|
|
|
- await this.context.globalState.update(key, value)
|
|
|
+ await this.contextProxy.updateGlobalState(key, value)
|
|
|
}
|
|
|
|
|
|
async getGlobalState(key: GlobalStateKey) {
|
|
|
- return await this.context.globalState.get(key)
|
|
|
+ return await this.contextProxy.getGlobalState(key)
|
|
|
}
|
|
|
|
|
|
// secrets
|
|
|
|
|
|
public async storeSecret(key: SecretKey, value?: string) {
|
|
|
- if (value) {
|
|
|
- await this.context.secrets.store(key, value)
|
|
|
- } else {
|
|
|
- await this.context.secrets.delete(key)
|
|
|
- }
|
|
|
+ await this.contextProxy.storeSecret(key, value)
|
|
|
}
|
|
|
|
|
|
private async getSecret(key: SecretKey) {
|
|
|
- return await this.context.secrets.get(key)
|
|
|
+ return await this.contextProxy.getSecret(key)
|
|
|
}
|
|
|
|
|
|
// dev
|
|
|
@@ -2669,26 +2430,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|
|
}
|
|
|
|
|
|
for (const key of this.context.globalState.keys()) {
|
|
|
- await this.context.globalState.update(key, undefined)
|
|
|
+ await this.contextProxy.updateGlobalState(key, undefined)
|
|
|
}
|
|
|
- const secretKeys: SecretKey[] = [
|
|
|
- "apiKey",
|
|
|
- "glamaApiKey",
|
|
|
- "openRouterApiKey",
|
|
|
- "awsAccessKey",
|
|
|
- "awsSecretKey",
|
|
|
- "awsSessionToken",
|
|
|
- "openAiApiKey",
|
|
|
- "geminiApiKey",
|
|
|
- "openAiNativeApiKey",
|
|
|
- "deepSeekApiKey",
|
|
|
- "mistralApiKey",
|
|
|
- "unboundApiKey",
|
|
|
- "requestyApiKey",
|
|
|
- ]
|
|
|
- for (const key of secretKeys) {
|
|
|
+
|
|
|
+ for (const key of SECRET_KEYS) {
|
|
|
await this.storeSecret(key, undefined)
|
|
|
}
|
|
|
+
|
|
|
await this.configManager.resetAllConfigs()
|
|
|
await this.customModesManager.resetCustomModes()
|
|
|
await this.removeClineFromStack()
|