mirror of
https://github.com/cline/cline.git
synced 2026-09-05 05:02:27 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5af5a261b3 | |||
| 94739d7a44 | |||
| 5e91b075d9 | |||
| 7bf9c3138c | |||
| 74243ebc8b | |||
| 407268c1aa | |||
| 9a95e509eb | |||
| 28022f56fd | |||
| 28a71ecd85 | |||
| 34e2f0dc41 | |||
| 4b1429c667 | |||
| a6eb8765c5 | |||
| 0bb13b1a36 | |||
| 574f82a171 | |||
| 21eaa754ac | |||
| 5d47aa5f8f | |||
| f2c9b4f42b |
+115
-84
@@ -168,88 +168,119 @@ message LiteLLMModelInfo {
|
||||
|
||||
// Main ApiConfiguration message
|
||||
message ModelsApiConfiguration {
|
||||
// From ApiHandlerOptions (excluding onRetryAttempt function)
|
||||
optional string api_model_id = 1;
|
||||
optional string api_key = 2;
|
||||
optional string cline_account_id = 3;
|
||||
optional string task_id = 4;
|
||||
optional string lite_llm_base_url = 5;
|
||||
optional string lite_llm_model_id = 6;
|
||||
optional string lite_llm_api_key = 7;
|
||||
optional bool lite_llm_use_prompt_cache = 8;
|
||||
map<string, string> open_ai_headers = 9;
|
||||
optional LiteLLMModelInfo lite_llm_model_info = 10;
|
||||
optional string anthropic_base_url = 11;
|
||||
optional string open_router_api_key = 12;
|
||||
optional string open_router_model_id = 13;
|
||||
optional OpenRouterModelInfo open_router_model_info = 14;
|
||||
optional string open_router_provider_sorting = 15;
|
||||
optional string aws_access_key = 16;
|
||||
optional string aws_secret_key = 17;
|
||||
optional string aws_session_token = 18;
|
||||
optional string aws_region = 19;
|
||||
optional bool aws_use_cross_region_inference = 20;
|
||||
optional bool aws_bedrock_use_prompt_cache = 21;
|
||||
optional bool aws_use_profile = 22;
|
||||
optional string aws_profile = 23;
|
||||
optional string aws_bedrock_endpoint = 24;
|
||||
optional bool aws_bedrock_custom_selected = 25;
|
||||
optional string aws_bedrock_custom_model_base_id = 26;
|
||||
optional string vertex_project_id = 27;
|
||||
optional string vertex_region = 28;
|
||||
optional string open_ai_base_url = 29;
|
||||
optional string open_ai_api_key = 30;
|
||||
optional string open_ai_model_id = 31;
|
||||
optional OpenAiCompatibleModelInfo open_ai_model_info = 32;
|
||||
optional string ollama_model_id = 33;
|
||||
optional string ollama_base_url = 34;
|
||||
optional string ollama_api_options_ctx_num = 35;
|
||||
optional string lm_studio_model_id = 36;
|
||||
optional string lm_studio_base_url = 37;
|
||||
optional string gemini_api_key = 38;
|
||||
optional string gemini_base_url = 39;
|
||||
optional string open_ai_native_api_key = 40;
|
||||
optional string deep_seek_api_key = 41;
|
||||
optional string requesty_api_key = 42;
|
||||
optional string requesty_model_id = 43;
|
||||
optional OpenRouterModelInfo requesty_model_info = 44;
|
||||
optional string together_api_key = 45;
|
||||
optional string together_model_id = 46;
|
||||
optional string fireworks_api_key = 47;
|
||||
optional string fireworks_model_id = 48;
|
||||
optional int32 fireworks_model_max_completion_tokens = 49;
|
||||
optional int32 fireworks_model_max_tokens = 50;
|
||||
optional string qwen_api_key = 51;
|
||||
optional string doubao_api_key = 52;
|
||||
optional string mistral_api_key = 53;
|
||||
optional string azure_api_version = 54;
|
||||
optional LanguageModelChatSelector vs_code_lm_model_selector = 55;
|
||||
optional string qwen_api_line = 56;
|
||||
optional string nebius_api_key = 57;
|
||||
optional string asksage_api_url = 58;
|
||||
optional string asksage_api_key = 59;
|
||||
optional string xai_api_key = 60;
|
||||
optional int32 thinking_budget_tokens = 61;
|
||||
optional string reasoning_effort = 62;
|
||||
optional string sambanova_api_key = 63;
|
||||
optional string cerebras_api_key = 64;
|
||||
optional int32 request_timeout_ms = 65;
|
||||
optional ApiProvider api_provider = 66;
|
||||
repeated string favorited_model_ids = 67;
|
||||
optional string sap_ai_core_client_id = 68;
|
||||
optional string sap_ai_core_client_secret = 69;
|
||||
optional string sap_ai_resource_group = 70;
|
||||
optional string sap_ai_core_token_url = 71;
|
||||
optional string sap_ai_core_base_url = 72;
|
||||
optional string claude_code_path = 73;
|
||||
optional string aws_authentication = 74;
|
||||
optional string aws_bedrock_api_key = 75;
|
||||
optional string moonshot_api_key = 76;
|
||||
optional string moonshot_api_line = 77;
|
||||
optional string groq_api_key = 78;
|
||||
optional string groq_model_id = 79;
|
||||
optional OpenRouterModelInfo groq_model_info = 80;
|
||||
optional string hugging_face_api_key = 81;
|
||||
optional string hugging_face_model_id = 82;
|
||||
optional OpenRouterModelInfo hugging_face_model_info = 83;
|
||||
// Global configuration fields (not mode-specific)
|
||||
optional string api_key = 1;
|
||||
optional string cline_api_key = 2;
|
||||
optional string task_id = 3;
|
||||
optional string lite_llm_base_url = 4;
|
||||
optional string lite_llm_api_key = 5;
|
||||
optional bool lite_llm_use_prompt_cache = 6;
|
||||
map<string, string> open_ai_headers = 7;
|
||||
optional string anthropic_base_url = 8;
|
||||
optional string open_router_api_key = 9;
|
||||
optional string open_router_provider_sorting = 10;
|
||||
optional string aws_access_key = 11;
|
||||
optional string aws_secret_key = 12;
|
||||
optional string aws_session_token = 13;
|
||||
optional string aws_region = 14;
|
||||
optional bool aws_use_cross_region_inference = 15;
|
||||
optional bool aws_bedrock_use_prompt_cache = 16;
|
||||
optional bool aws_use_profile = 17;
|
||||
optional string aws_profile = 18;
|
||||
optional string aws_bedrock_endpoint = 19;
|
||||
optional string claude_code_path = 20;
|
||||
optional string vertex_project_id = 21;
|
||||
optional string vertex_region = 22;
|
||||
optional string open_ai_base_url = 23;
|
||||
optional string open_ai_api_key = 24;
|
||||
optional string ollama_base_url = 25;
|
||||
optional string ollama_api_options_ctx_num = 26;
|
||||
optional string lm_studio_base_url = 27;
|
||||
optional string gemini_api_key = 28;
|
||||
optional string gemini_base_url = 29;
|
||||
optional string open_ai_native_api_key = 30;
|
||||
optional string deep_seek_api_key = 31;
|
||||
optional string requesty_api_key = 32;
|
||||
optional string together_api_key = 33;
|
||||
optional string fireworks_api_key = 34;
|
||||
optional int32 fireworks_model_max_completion_tokens = 35;
|
||||
optional int32 fireworks_model_max_tokens = 36;
|
||||
optional string qwen_api_key = 37;
|
||||
optional string doubao_api_key = 38;
|
||||
optional string mistral_api_key = 39;
|
||||
optional string azure_api_version = 40;
|
||||
optional string qwen_api_line = 41;
|
||||
optional string nebius_api_key = 42;
|
||||
optional string asksage_api_url = 43;
|
||||
optional string asksage_api_key = 44;
|
||||
optional string xai_api_key = 45;
|
||||
optional string sambanova_api_key = 46;
|
||||
optional string cerebras_api_key = 47;
|
||||
optional int32 request_timeout_ms = 48;
|
||||
optional string sap_ai_core_client_id = 49;
|
||||
optional string sap_ai_core_client_secret = 50;
|
||||
optional string sap_ai_resource_group = 51;
|
||||
optional string sap_ai_core_token_url = 52;
|
||||
optional string sap_ai_core_base_url = 53;
|
||||
optional string moonshot_api_key = 54;
|
||||
optional string moonshot_api_line = 55;
|
||||
optional string aws_authentication = 56;
|
||||
optional string aws_bedrock_api_key = 57;
|
||||
optional string cline_account_id = 58;
|
||||
optional string groq_api_key = 59;
|
||||
optional string hugging_face_api_key = 60;
|
||||
|
||||
// Plan mode configurations
|
||||
optional ApiProvider plan_mode_api_provider = 100;
|
||||
optional string plan_mode_api_model_id = 101;
|
||||
optional int32 plan_mode_thinking_budget_tokens = 102;
|
||||
optional string plan_mode_reasoning_effort = 103;
|
||||
optional LanguageModelChatSelector plan_mode_vs_code_lm_model_selector = 104;
|
||||
optional bool plan_mode_aws_bedrock_custom_selected = 105;
|
||||
optional string plan_mode_aws_bedrock_custom_model_base_id = 106;
|
||||
optional string plan_mode_open_router_model_id = 107;
|
||||
optional OpenRouterModelInfo plan_mode_open_router_model_info = 108;
|
||||
optional string plan_mode_open_ai_model_id = 109;
|
||||
optional OpenAiCompatibleModelInfo plan_mode_open_ai_model_info = 110;
|
||||
optional string plan_mode_ollama_model_id = 111;
|
||||
optional string plan_mode_lm_studio_model_id = 112;
|
||||
optional string plan_mode_lite_llm_model_id = 113;
|
||||
optional LiteLLMModelInfo plan_mode_lite_llm_model_info = 114;
|
||||
optional string plan_mode_requesty_model_id = 115;
|
||||
optional OpenRouterModelInfo plan_mode_requesty_model_info = 116;
|
||||
optional string plan_mode_together_model_id = 117;
|
||||
optional string plan_mode_fireworks_model_id = 118;
|
||||
optional string plan_mode_sap_ai_core_model_id = 119;
|
||||
optional string plan_mode_groq_model_id = 120;
|
||||
optional OpenRouterModelInfo plan_mode_groq_model_info = 121;
|
||||
optional string plan_mode_hugging_face_model_id = 122;
|
||||
optional OpenRouterModelInfo plan_mode_hugging_face_model_info = 123;
|
||||
|
||||
// Act mode configurations
|
||||
optional ApiProvider act_mode_api_provider = 200;
|
||||
optional string act_mode_api_model_id = 201;
|
||||
optional int32 act_mode_thinking_budget_tokens = 202;
|
||||
optional string act_mode_reasoning_effort = 203;
|
||||
optional LanguageModelChatSelector act_mode_vs_code_lm_model_selector = 204;
|
||||
optional bool act_mode_aws_bedrock_custom_selected = 205;
|
||||
optional string act_mode_aws_bedrock_custom_model_base_id = 206;
|
||||
optional string act_mode_open_router_model_id = 207;
|
||||
optional OpenRouterModelInfo act_mode_open_router_model_info = 208;
|
||||
optional string act_mode_open_ai_model_id = 209;
|
||||
optional OpenAiCompatibleModelInfo act_mode_open_ai_model_info = 210;
|
||||
optional string act_mode_ollama_model_id = 211;
|
||||
optional string act_mode_lm_studio_model_id = 212;
|
||||
optional string act_mode_lite_llm_model_id = 213;
|
||||
optional LiteLLMModelInfo act_mode_lite_llm_model_info = 214;
|
||||
optional string act_mode_requesty_model_id = 215;
|
||||
optional OpenRouterModelInfo act_mode_requesty_model_info = 216;
|
||||
optional string act_mode_together_model_id = 217;
|
||||
optional string act_mode_fireworks_model_id = 218;
|
||||
optional string act_mode_sap_ai_core_model_id = 219;
|
||||
optional string act_mode_groq_model_id = 220;
|
||||
optional OpenRouterModelInfo act_mode_groq_model_info = 221;
|
||||
optional string act_mode_hugging_face_model_id = 222;
|
||||
optional OpenRouterModelInfo act_mode_hugging_face_model_info = 223;
|
||||
|
||||
repeated string favorited_model_ids = 300;
|
||||
}
|
||||
|
||||
+102
-115
@@ -118,126 +118,113 @@ message UpdateSettingsRequest {
|
||||
|
||||
// Complete API Configuration message
|
||||
message ApiConfiguration {
|
||||
// Core API fields
|
||||
optional string api_provider = 1;
|
||||
optional string api_model_id = 2;
|
||||
optional string api_key = 3; // anthropic
|
||||
optional string api_base_url = 4;
|
||||
// Global configuration fields (not mode-specific)
|
||||
optional string api_key = 1; // anthropic
|
||||
optional string cline_api_key = 2;
|
||||
optional string task_id = 3;
|
||||
optional string lite_llm_base_url = 4;
|
||||
optional string lite_llm_api_key = 5;
|
||||
optional bool lite_llm_use_prompt_cache = 6;
|
||||
optional string openai_headers = 7; // JSON string
|
||||
optional string anthropic_base_url = 8;
|
||||
optional string openrouter_api_key = 9;
|
||||
optional string openrouter_provider_sorting = 10;
|
||||
optional string aws_access_key = 11;
|
||||
optional string aws_secret_key = 12;
|
||||
optional string aws_session_token = 13;
|
||||
optional string aws_region = 14;
|
||||
optional bool aws_use_cross_region_inference = 15;
|
||||
optional bool aws_bedrock_use_prompt_cache = 16;
|
||||
optional bool aws_use_profile = 17;
|
||||
optional string aws_profile = 18;
|
||||
optional string aws_bedrock_endpoint = 19;
|
||||
optional string claude_code_path = 20;
|
||||
optional string vertex_project_id = 21;
|
||||
optional string vertex_region = 22;
|
||||
optional string openai_base_url = 23;
|
||||
optional string openai_api_key = 24;
|
||||
optional string ollama_base_url = 25;
|
||||
optional string ollama_api_options_ctx_num = 26;
|
||||
optional string lm_studio_base_url = 27;
|
||||
optional string gemini_api_key = 28;
|
||||
optional string gemini_base_url = 29;
|
||||
optional string openai_native_api_key = 30;
|
||||
optional string deep_seek_api_key = 31;
|
||||
optional string requesty_api_key = 32;
|
||||
optional string together_api_key = 33;
|
||||
optional string fireworks_api_key = 34;
|
||||
optional int64 fireworks_model_max_completion_tokens = 35;
|
||||
optional int64 fireworks_model_max_tokens = 36;
|
||||
optional string qwen_api_key = 37;
|
||||
optional string doubao_api_key = 38;
|
||||
optional string mistral_api_key = 39;
|
||||
optional string azure_api_version = 40;
|
||||
optional string qwen_api_line = 41;
|
||||
optional string nebius_api_key = 42;
|
||||
optional string asksage_api_url = 43;
|
||||
optional string asksage_api_key = 44;
|
||||
optional string xai_api_key = 45;
|
||||
optional string sambanova_api_key = 46;
|
||||
optional string cerebras_api_key = 47;
|
||||
optional int64 request_timeout_ms = 48;
|
||||
optional string sap_ai_core_client_id = 49;
|
||||
optional string sap_ai_core_client_secret = 50;
|
||||
optional string sap_ai_resource_group = 51;
|
||||
optional string sap_ai_core_token_url = 52;
|
||||
optional string sap_ai_core_base_url = 53;
|
||||
optional string moonshot_api_key = 54;
|
||||
optional string moonshot_api_line = 55;
|
||||
|
||||
// Provider-specific API keys
|
||||
optional string cline_account_id = 5;
|
||||
optional string openrouter_api_key = 6;
|
||||
optional string anthropic_base_url = 7;
|
||||
optional string openai_api_key = 8;
|
||||
optional string openai_native_api_key = 9;
|
||||
optional string gemini_api_key = 10;
|
||||
optional string deepseek_api_key = 11;
|
||||
optional string requesty_api_key = 12;
|
||||
optional string together_api_key = 13;
|
||||
optional string fireworks_api_key = 14;
|
||||
optional string qwen_api_key = 15;
|
||||
optional string doubao_api_key = 16;
|
||||
optional string mistral_api_key = 17;
|
||||
optional string nebius_api_key = 18;
|
||||
optional string asksage_api_key = 19;
|
||||
optional string xai_api_key = 20;
|
||||
optional string sambanova_api_key = 21;
|
||||
optional string cerebras_api_key = 22;
|
||||
// Plan mode configurations
|
||||
optional string plan_mode_api_provider = 100;
|
||||
optional string plan_mode_api_model_id = 101;
|
||||
optional int64 plan_mode_thinking_budget_tokens = 102;
|
||||
optional string plan_mode_reasoning_effort = 103;
|
||||
optional string plan_mode_vscode_lm_model_selector = 104; // JSON string
|
||||
optional bool plan_mode_aws_bedrock_custom_selected = 105;
|
||||
optional string plan_mode_aws_bedrock_custom_model_base_id = 106;
|
||||
optional string plan_mode_openrouter_model_id = 107;
|
||||
optional string plan_mode_openrouter_model_info = 108; // JSON string
|
||||
optional string plan_mode_openai_model_id = 109;
|
||||
optional string plan_mode_openai_model_info = 110; // JSON string
|
||||
optional string plan_mode_ollama_model_id = 111;
|
||||
optional string plan_mode_lm_studio_model_id = 112;
|
||||
optional string plan_mode_lite_llm_model_id = 113;
|
||||
optional string plan_mode_lite_llm_model_info = 114; // JSON string
|
||||
optional string plan_mode_requesty_model_id = 115;
|
||||
optional string plan_mode_requesty_model_info = 116; // JSON string
|
||||
optional string plan_mode_together_model_id = 117;
|
||||
optional string plan_mode_fireworks_model_id = 118;
|
||||
optional string plan_mode_sap_ai_core_model_id = 119;
|
||||
|
||||
// Model IDs
|
||||
optional string openrouter_model_id = 23;
|
||||
optional string openai_model_id = 24;
|
||||
optional string anthropic_model_id = 25;
|
||||
optional string bedrock_model_id = 26;
|
||||
optional string vertex_model_id = 27;
|
||||
optional string gemini_model_id = 28;
|
||||
optional string ollama_model_id = 29;
|
||||
optional string lm_studio_model_id = 30;
|
||||
optional string litellm_model_id = 31;
|
||||
optional string requesty_model_id = 32;
|
||||
optional string together_model_id = 33;
|
||||
optional string fireworks_model_id = 34;
|
||||
|
||||
// AWS Bedrock fields
|
||||
optional bool aws_bedrock_custom_selected = 35;
|
||||
optional string aws_bedrock_custom_model_base_id = 36;
|
||||
optional string aws_access_key = 37;
|
||||
optional string aws_secret_key = 38;
|
||||
optional string aws_session_token = 39;
|
||||
optional string aws_region = 40;
|
||||
optional bool aws_use_cross_region_inference = 41;
|
||||
optional bool aws_bedrock_use_prompt_cache = 42;
|
||||
optional bool aws_use_profile = 43;
|
||||
optional string aws_profile = 44;
|
||||
optional string aws_bedrock_endpoint = 45;
|
||||
|
||||
// Vertex AI fields
|
||||
optional string vertex_project_id = 46;
|
||||
optional string vertex_region = 47;
|
||||
|
||||
// Base URLs and endpoints
|
||||
optional string openai_base_url = 48;
|
||||
optional string ollama_base_url = 49;
|
||||
optional string lm_studio_base_url = 50;
|
||||
optional string gemini_base_url = 51;
|
||||
optional string litellm_base_url = 52;
|
||||
optional string asksage_api_url = 53;
|
||||
|
||||
// LiteLLM specific fields
|
||||
optional string litellm_api_key = 54;
|
||||
optional bool litellm_use_prompt_cache = 55;
|
||||
|
||||
// Model configuration
|
||||
optional int64 thinking_budget_tokens = 56;
|
||||
optional string reasoning_effort = 57;
|
||||
optional int64 request_timeout_ms = 58;
|
||||
|
||||
// Fireworks specific
|
||||
optional int64 fireworks_model_max_completion_tokens = 59;
|
||||
optional int64 fireworks_model_max_tokens = 60;
|
||||
|
||||
// Azure specific
|
||||
optional string azure_api_version = 61;
|
||||
|
||||
// Ollama specific
|
||||
optional string ollama_api_options_ctx_num = 62;
|
||||
|
||||
// Qwen specific
|
||||
optional string qwen_api_line = 63;
|
||||
|
||||
// OpenRouter specific
|
||||
optional string openrouter_provider_sorting = 64;
|
||||
|
||||
// VSCode LM (stored as JSON string due to complex type)
|
||||
optional string vscode_lm_model_selector = 65;
|
||||
|
||||
// Model info objects (stored as JSON strings)
|
||||
optional string openrouter_model_info = 66;
|
||||
optional string openai_model_info = 67;
|
||||
optional string requesty_model_info = 68;
|
||||
optional string litellm_model_info = 69;
|
||||
|
||||
// OpenAI headers (stored as JSON string)
|
||||
optional string openai_headers = 70;
|
||||
// Act mode configurations
|
||||
optional string act_mode_api_provider = 200;
|
||||
optional string act_mode_api_model_id = 201;
|
||||
optional int64 act_mode_thinking_budget_tokens = 202;
|
||||
optional string act_mode_reasoning_effort = 203;
|
||||
optional string act_mode_vscode_lm_model_selector = 204; // JSON string
|
||||
optional bool act_mode_aws_bedrock_custom_selected = 205;
|
||||
optional string act_mode_aws_bedrock_custom_model_base_id = 206;
|
||||
optional string act_mode_openrouter_model_id = 207;
|
||||
optional string act_mode_openrouter_model_info = 208; // JSON string
|
||||
optional string act_mode_openai_model_id = 209;
|
||||
optional string act_mode_openai_model_info = 210; // JSON string
|
||||
optional string act_mode_ollama_model_id = 211;
|
||||
optional string act_mode_lm_studio_model_id = 212;
|
||||
optional string act_mode_lite_llm_model_id = 213;
|
||||
optional string act_mode_lite_llm_model_info = 214; // JSON string
|
||||
optional string act_mode_requesty_model_id = 215;
|
||||
optional string act_mode_requesty_model_info = 216; // JSON string
|
||||
optional string act_mode_together_model_id = 217;
|
||||
optional string act_mode_fireworks_model_id = 218;
|
||||
optional string act_mode_sap_ai_core_model_id = 219;
|
||||
|
||||
// Favorited model IDs
|
||||
repeated string favorited_model_ids = 71;
|
||||
|
||||
// SAP AI Core specific
|
||||
optional string sap_ai_core_client_id = 72;
|
||||
optional string sap_ai_core_client_secret = 73;
|
||||
optional string sap_ai_core_base_url = 74;
|
||||
optional string sap_ai_core_token_url = 75;
|
||||
optional string sap_ai_resource_group = 76;
|
||||
|
||||
// Claude Code specific
|
||||
optional string claude_code_path = 77;
|
||||
repeated string favorited_model_ids = 300;
|
||||
|
||||
// Extension fields for Bedrock Api Keys
|
||||
optional string aws_authentication = 78;
|
||||
optional string aws_bedrock_api_key = 79;
|
||||
optional string aws_authentication = 301;
|
||||
optional string aws_bedrock_api_key = 302;
|
||||
|
||||
// Moonshot
|
||||
optional string moonshot_api_key = 80;
|
||||
optional string moonshot_api_line = 81;
|
||||
optional string cline_account_id = 303;
|
||||
}
|
||||
|
||||
+93
-64
@@ -29,6 +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 { HuggingFaceHandler } from "./providers/huggingface"
|
||||
|
||||
export interface ApiHandler {
|
||||
@@ -41,27 +42,33 @@ export interface SingleCompletionHandler {
|
||||
completePrompt(prompt: string): Promise<string>
|
||||
}
|
||||
|
||||
function createHandlerForProvider(apiProvider: string | undefined, options: Omit<ApiConfiguration, "apiProvider">): ApiHandler {
|
||||
function createHandlerForProvider(
|
||||
apiProvider: string | undefined,
|
||||
options: Omit<ApiConfiguration, "apiProvider">,
|
||||
mode: Mode,
|
||||
): ApiHandler {
|
||||
switch (apiProvider) {
|
||||
case "anthropic":
|
||||
return new AnthropicHandler({
|
||||
apiKey: options.apiKey,
|
||||
anthropicBaseUrl: options.anthropicBaseUrl,
|
||||
apiModelId: options.apiModelId,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
case "openrouter":
|
||||
return new OpenRouterHandler({
|
||||
openRouterApiKey: options.openRouterApiKey,
|
||||
openRouterModelId: options.openRouterModelId,
|
||||
openRouterModelInfo: options.openRouterModelInfo,
|
||||
openRouterModelId: mode === "plan" ? options.planModeOpenRouterModelId : options.actModeOpenRouterModelId,
|
||||
openRouterModelInfo: mode === "plan" ? options.planModeOpenRouterModelInfo : options.actModeOpenRouterModelInfo,
|
||||
openRouterProviderSorting: options.openRouterProviderSorting,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
case "bedrock":
|
||||
return new AwsBedrockHandler({
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
awsAccessKey: options.awsAccessKey,
|
||||
awsSecretKey: options.awsSecretKey,
|
||||
awsSessionToken: options.awsSessionToken,
|
||||
@@ -73,16 +80,20 @@ function createHandlerForProvider(apiProvider: string | undefined, options: Omit
|
||||
awsUseProfile: options.awsUseProfile,
|
||||
awsProfile: options.awsProfile,
|
||||
awsBedrockEndpoint: options.awsBedrockEndpoint,
|
||||
awsBedrockCustomSelected: options.awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId: options.awsBedrockCustomModelBaseId,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
awsBedrockCustomSelected:
|
||||
mode === "plan" ? options.planModeAwsBedrockCustomSelected : options.actModeAwsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId:
|
||||
mode === "plan" ? options.planModeAwsBedrockCustomModelBaseId : options.actModeAwsBedrockCustomModelBaseId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
case "vertex":
|
||||
return new VertexHandler({
|
||||
vertexProjectId: options.vertexProjectId,
|
||||
vertexRegion: options.vertexRegion,
|
||||
apiModelId: options.apiModelId,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
geminiApiKey: options.geminiApiKey,
|
||||
geminiBaseUrl: options.geminiBaseUrl,
|
||||
taskId: options.taskId,
|
||||
@@ -93,21 +104,21 @@ function createHandlerForProvider(apiProvider: string | undefined, options: Omit
|
||||
openAiBaseUrl: options.openAiBaseUrl,
|
||||
azureApiVersion: options.azureApiVersion,
|
||||
openAiHeaders: options.openAiHeaders,
|
||||
openAiModelId: options.openAiModelId,
|
||||
openAiModelInfo: options.openAiModelInfo,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
openAiModelId: mode === "plan" ? options.planModeOpenAiModelId : options.actModeOpenAiModelId,
|
||||
openAiModelInfo: mode === "plan" ? options.planModeOpenAiModelInfo : options.actModeOpenAiModelInfo,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
})
|
||||
case "ollama":
|
||||
return new OllamaHandler({
|
||||
ollamaBaseUrl: options.ollamaBaseUrl,
|
||||
ollamaModelId: options.ollamaModelId,
|
||||
ollamaModelId: mode === "plan" ? options.planModeOllamaModelId : options.actModeOllamaModelId,
|
||||
ollamaApiOptionsCtxNum: options.ollamaApiOptionsCtxNum,
|
||||
requestTimeoutMs: options.requestTimeoutMs,
|
||||
})
|
||||
case "lmstudio":
|
||||
return new LmStudioHandler({
|
||||
lmStudioBaseUrl: options.lmStudioBaseUrl,
|
||||
lmStudioModelId: options.lmStudioModelId,
|
||||
lmStudioModelId: mode === "plan" ? options.planModeLmStudioModelId : options.actModeLmStudioModelId,
|
||||
})
|
||||
case "gemini":
|
||||
return new GeminiHandler({
|
||||
@@ -115,78 +126,85 @@ function createHandlerForProvider(apiProvider: string | undefined, options: Omit
|
||||
vertexRegion: options.vertexRegion,
|
||||
geminiApiKey: options.geminiApiKey,
|
||||
geminiBaseUrl: options.geminiBaseUrl,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
apiModelId: options.apiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
taskId: options.taskId,
|
||||
})
|
||||
case "openai-native":
|
||||
return new OpenAiNativeHandler({
|
||||
openAiNativeApiKey: options.openAiNativeApiKey,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
apiModelId: options.apiModelId,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "deepseek":
|
||||
return new DeepSeekHandler({
|
||||
deepSeekApiKey: options.deepSeekApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "requesty":
|
||||
return new RequestyHandler({
|
||||
requestyApiKey: options.requestyApiKey,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
requestyModelId: options.requestyModelId,
|
||||
requestyModelInfo: options.requestyModelInfo,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
requestyModelId: mode === "plan" ? options.planModeRequestyModelId : options.actModeRequestyModelId,
|
||||
requestyModelInfo: mode === "plan" ? options.planModeRequestyModelInfo : options.actModeRequestyModelInfo,
|
||||
})
|
||||
case "fireworks":
|
||||
return new FireworksHandler({
|
||||
fireworksApiKey: options.fireworksApiKey,
|
||||
fireworksModelId: options.fireworksModelId,
|
||||
fireworksModelId: mode === "plan" ? options.planModeFireworksModelId : options.actModeFireworksModelId,
|
||||
fireworksModelMaxCompletionTokens: options.fireworksModelMaxCompletionTokens,
|
||||
fireworksModelMaxTokens: options.fireworksModelMaxTokens,
|
||||
})
|
||||
case "together":
|
||||
return new TogetherHandler({
|
||||
togetherApiKey: options.togetherApiKey,
|
||||
togetherModelId: options.togetherModelId,
|
||||
togetherModelId: mode === "plan" ? options.planModeTogetherModelId : options.actModeTogetherModelId,
|
||||
})
|
||||
case "qwen":
|
||||
return new QwenHandler({
|
||||
qwenApiKey: options.qwenApiKey,
|
||||
qwenApiLine: options.qwenApiLine,
|
||||
apiModelId: options.apiModelId,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
case "doubao":
|
||||
return new DoubaoHandler({
|
||||
doubaoApiKey: options.doubaoApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "mistral":
|
||||
return new MistralHandler({
|
||||
mistralApiKey: options.mistralApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "vscode-lm":
|
||||
return new VsCodeLmHandler({
|
||||
vsCodeLmModelSelector: options.vsCodeLmModelSelector,
|
||||
vsCodeLmModelSelector:
|
||||
mode === "plan" ? options.planModeVsCodeLmModelSelector : options.actModeVsCodeLmModelSelector,
|
||||
})
|
||||
case "cline":
|
||||
return new ClineHandler({
|
||||
clineAccountId: options.clineAccountId,
|
||||
taskId: options.taskId,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
openRouterProviderSorting: options.openRouterProviderSorting,
|
||||
openRouterModelId: options.openRouterModelId,
|
||||
openRouterModelInfo: options.openRouterModelInfo,
|
||||
openRouterModelId: mode === "plan" ? options.planModeOpenRouterModelId : options.actModeOpenRouterModelId,
|
||||
openRouterModelInfo: mode === "plan" ? options.planModeOpenRouterModelInfo : options.actModeOpenRouterModelInfo,
|
||||
})
|
||||
case "litellm":
|
||||
return new LiteLlmHandler({
|
||||
liteLlmApiKey: options.liteLlmApiKey,
|
||||
liteLlmBaseUrl: options.liteLlmBaseUrl,
|
||||
liteLlmModelId: options.liteLlmModelId,
|
||||
liteLlmModelInfo: options.liteLlmModelInfo,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
liteLlmModelId: mode === "plan" ? options.planModeLiteLlmModelId : options.actModeLiteLlmModelId,
|
||||
liteLlmModelInfo: mode === "plan" ? options.planModeLiteLlmModelInfo : options.actModeLiteLlmModelInfo,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
liteLlmUsePromptCache: options.liteLlmUsePromptCache,
|
||||
taskId: options.taskId,
|
||||
})
|
||||
@@ -194,46 +212,48 @@ function createHandlerForProvider(apiProvider: string | undefined, options: Omit
|
||||
return new MoonshotHandler({
|
||||
moonshotApiKey: options.moonshotApiKey,
|
||||
moonshotApiLine: options.moonshotApiLine,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "huggingface":
|
||||
return new HuggingFaceHandler({
|
||||
huggingFaceApiKey: options.huggingFaceApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
huggingFaceModelId: mode === "plan" ? options.planModeHuggingFaceModelId : options.actModeHuggingFaceModelId,
|
||||
huggingFaceModelInfo:
|
||||
mode === "plan" ? options.planModeHuggingFaceModelInfo : options.actModeHuggingFaceModelInfo,
|
||||
})
|
||||
case "nebius":
|
||||
return new NebiusHandler({
|
||||
nebiusApiKey: options.nebiusApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "asksage":
|
||||
return new AskSageHandler({
|
||||
asksageApiKey: options.asksageApiKey,
|
||||
asksageApiUrl: options.asksageApiUrl,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "xai":
|
||||
return new XAIHandler({
|
||||
xaiApiKey: options.xaiApiKey,
|
||||
reasoningEffort: options.reasoningEffort,
|
||||
apiModelId: options.apiModelId,
|
||||
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "sambanova":
|
||||
return new SambanovaHandler({
|
||||
sambanovaApiKey: options.sambanovaApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "cerebras":
|
||||
return new CerebrasHandler({
|
||||
cerebrasApiKey: options.cerebrasApiKey,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "groq":
|
||||
return new GroqHandler({
|
||||
groqApiKey: options.groqApiKey,
|
||||
groqModelId: options.groqModelId,
|
||||
groqModelInfo: options.groqModelInfo,
|
||||
apiModelId: options.apiModelId,
|
||||
groqModelId: mode === "plan" ? options.planModeGroqModelId : options.actModeGroqModelId,
|
||||
groqModelInfo: mode === "plan" ? options.planModeGroqModelInfo : options.actModeGroqModelInfo,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "sapaicore":
|
||||
return new SapAiCoreHandler({
|
||||
@@ -242,37 +262,46 @@ function createHandlerForProvider(apiProvider: string | undefined, options: Omit
|
||||
sapAiCoreTokenUrl: options.sapAiCoreTokenUrl,
|
||||
sapAiResourceGroup: options.sapAiResourceGroup,
|
||||
sapAiCoreBaseUrl: options.sapAiCoreBaseUrl,
|
||||
apiModelId: options.apiModelId,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
})
|
||||
case "claude-code":
|
||||
return new ClaudeCodeHandler({
|
||||
claudeCodePath: options.claudeCodePath,
|
||||
apiModelId: options.apiModelId,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
default:
|
||||
return new AnthropicHandler({
|
||||
apiKey: options.apiKey,
|
||||
anthropicBaseUrl: options.anthropicBaseUrl,
|
||||
apiModelId: options.apiModelId,
|
||||
thinkingBudgetTokens: options.thinkingBudgetTokens,
|
||||
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
||||
const { apiProvider, ...options } = configuration
|
||||
export function buildApiHandler(configuration: ApiConfiguration, mode: Mode): ApiHandler {
|
||||
const { planModeApiProvider, actModeApiProvider, ...options } = configuration
|
||||
|
||||
const apiProvider = mode === "plan" ? planModeApiProvider : actModeApiProvider
|
||||
|
||||
// Validate thinking budget tokens against model's maxTokens to prevent API errors
|
||||
// wrapped in a try-catch for safety, but this should never throw
|
||||
try {
|
||||
if (options.thinkingBudgetTokens && options.thinkingBudgetTokens > 0) {
|
||||
const handler = createHandlerForProvider(apiProvider, options)
|
||||
const thinkingBudgetTokens = mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens
|
||||
if (thinkingBudgetTokens && thinkingBudgetTokens > 0) {
|
||||
const handler = createHandlerForProvider(apiProvider, options, mode)
|
||||
|
||||
const modelInfo = handler.getModel().info
|
||||
if (modelInfo.maxTokens && options.thinkingBudgetTokens > modelInfo.maxTokens) {
|
||||
if (modelInfo.maxTokens && thinkingBudgetTokens > modelInfo.maxTokens) {
|
||||
const clippedValue = modelInfo.maxTokens - 1
|
||||
options.thinkingBudgetTokens = clippedValue
|
||||
if (mode === "plan") {
|
||||
options.planModeThinkingBudgetTokens = clippedValue
|
||||
} else {
|
||||
options.actModeThinkingBudgetTokens = clippedValue
|
||||
}
|
||||
} else {
|
||||
return handler // don't rebuild unless its necessary
|
||||
}
|
||||
@@ -281,5 +310,5 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
||||
console.error("buildApiHandler error:", error)
|
||||
}
|
||||
|
||||
return createHandlerForProvider(apiProvider, options)
|
||||
return createHandlerForProvider(apiProvider, options, mode)
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ describe("AwsBedrockHandler", () => {
|
||||
})
|
||||
|
||||
const mockOptions: ApiHandlerOptions = {
|
||||
apiModelId: "anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
actModeApiModelId: "anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
awsRegion: "us-east-1",
|
||||
awsAccessKey: "test-key",
|
||||
awsSecretKey: "test-secret",
|
||||
@@ -214,9 +214,9 @@ describe("AwsBedrockHandler", () => {
|
||||
awsBedrockUsePromptCache: false,
|
||||
awsUseCrossRegionInference: false,
|
||||
awsBedrockEndpoint: "",
|
||||
awsBedrockCustomSelected: false,
|
||||
awsBedrockCustomModelBaseId: undefined,
|
||||
thinkingBudgetTokens: 1600,
|
||||
actModeAwsBedrockCustomSelected: false,
|
||||
actModeAwsBedrockCustomModelBaseId: undefined,
|
||||
actModeThinkingBudgetTokens: 1600,
|
||||
}
|
||||
|
||||
const mockModelInfo = {
|
||||
@@ -616,8 +616,8 @@ describe("AwsBedrockHandler", () => {
|
||||
it("should return raw model ID for custom models", async () => {
|
||||
const customOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
awsBedrockCustomSelected: true,
|
||||
apiModelId:
|
||||
actModeAwsBedrockCustomSelected: true,
|
||||
actModeApiModelId:
|
||||
"arn:aws:bedrock:us-west-2:123456789012:custom-model/anthropic.claude-3-5-sonnet-20241022-v2:0/Qk8MMyLmRd",
|
||||
}
|
||||
const customHandler = new AwsBedrockHandler(customOptions)
|
||||
@@ -631,8 +631,8 @@ describe("AwsBedrockHandler", () => {
|
||||
it("should not encode custom model IDs with slashes", async () => {
|
||||
const customOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
awsBedrockCustomSelected: true,
|
||||
apiModelId: "my-namespace/my-custom-model",
|
||||
actModeAwsBedrockCustomSelected: true,
|
||||
actModeApiModelId: "my-namespace/my-custom-model",
|
||||
}
|
||||
const customHandler = new AwsBedrockHandler(customOptions)
|
||||
|
||||
@@ -680,8 +680,8 @@ describe("AwsBedrockHandler", () => {
|
||||
it("should not apply cross-region prefix for custom models even when enabled", async () => {
|
||||
const customCrossRegionOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
awsBedrockCustomSelected: true,
|
||||
apiModelId: "arn:aws:bedrock:us-west-2:123456789012:custom-model/my-model",
|
||||
actModeAwsBedrockCustomSelected: true,
|
||||
actModeApiModelId: "arn:aws:bedrock:us-west-2:123456789012:custom-model/my-model",
|
||||
awsUseCrossRegionInference: true,
|
||||
}
|
||||
const customCrossRegionHandler = new AwsBedrockHandler(customCrossRegionOptions)
|
||||
@@ -693,10 +693,10 @@ describe("AwsBedrockHandler", () => {
|
||||
it("should handle UltraThink model ARN correctly", async () => {
|
||||
const ultraThinkOptions: ApiHandlerOptions = {
|
||||
...mockOptions,
|
||||
awsBedrockCustomSelected: true,
|
||||
apiModelId:
|
||||
actModeAwsBedrockCustomSelected: true,
|
||||
actModeApiModelId:
|
||||
"arn:aws:bedrock:us-west-2:123456789012:custom-model/anthropic.claude-3-5-sonnet-20241022-v2:0/Qk8MMyLmRd",
|
||||
awsBedrockCustomModelBaseId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||
actModeAwsBedrockCustomModelBaseId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||
}
|
||||
const ultraThinkHandler = new AwsBedrockHandler(ultraThinkOptions)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("OllamaHandler", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
options = {
|
||||
ollamaModelId: "llama2",
|
||||
actModeOllamaModelId: "llama2",
|
||||
ollamaBaseUrl: "http://localhost:11434",
|
||||
}
|
||||
handler = new OllamaHandler(options)
|
||||
|
||||
@@ -13,7 +13,7 @@ interface AnthropicHandlerOptions {
|
||||
}
|
||||
|
||||
export class AnthropicHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private options: AnthropicHandlerOptions
|
||||
private client: Anthropic | undefined
|
||||
|
||||
constructor(options: AnthropicHandlerOptions) {
|
||||
|
||||
@@ -44,7 +44,7 @@ interface GeminiHandlerOptions {
|
||||
* 4. Separating immediate costs from ongoing costs to avoid double-counting
|
||||
*/
|
||||
export class GeminiHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private options: GeminiHandlerOptions
|
||||
private client: GoogleGenAI | undefined
|
||||
|
||||
constructor(options: GeminiHandlerOptions) {
|
||||
|
||||
@@ -9,7 +9,8 @@ import { ApiStream } from "../transform/stream"
|
||||
|
||||
interface HuggingFaceHandlerOptions {
|
||||
huggingFaceApiKey?: string
|
||||
apiModelId?: string
|
||||
huggingFaceModelId?: string
|
||||
huggingFaceModelInfo?: ModelInfo
|
||||
}
|
||||
|
||||
export class HuggingFaceHandler implements ApiHandler {
|
||||
@@ -115,7 +116,7 @@ export class HuggingFaceHandler implements ApiHandler {
|
||||
return this.cachedModel
|
||||
}
|
||||
|
||||
const modelId = this.options.apiModelId
|
||||
const modelId = this.options.huggingFaceModelId
|
||||
|
||||
// List all available models for debugging
|
||||
const availableModels = Object.keys(huggingFaceModels)
|
||||
|
||||
@@ -19,6 +19,15 @@ interface OpenRouterHandlerOptions {
|
||||
thinkingBudgetTokens?: number
|
||||
}
|
||||
|
||||
interface OpenRouterHandlerOptions {
|
||||
openRouterApiKey?: string
|
||||
openRouterModelId?: string
|
||||
openRouterModelInfo?: ModelInfo
|
||||
openRouterProviderSorting?: string
|
||||
reasoningEffort?: string
|
||||
thinkingBudgetTokens?: number
|
||||
}
|
||||
|
||||
export class OpenRouterHandler implements ApiHandler {
|
||||
private options: OpenRouterHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
@@ -14,6 +14,12 @@ interface XAIHandlerOptions {
|
||||
apiModelId?: string
|
||||
}
|
||||
|
||||
interface XAIHandlerOptions {
|
||||
xaiApiKey?: string
|
||||
reasoningEffort?: string
|
||||
apiModelId?: string
|
||||
}
|
||||
|
||||
export class XAIHandler implements ApiHandler {
|
||||
private options: XAIHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
+48
-160
@@ -10,7 +10,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, StoredChatSettings } from "@shared/ChatSettings"
|
||||
import { ChatSettings, Mode, StoredChatSettings } from "@shared/ChatSettings"
|
||||
import { ClineRulesToggles } from "@shared/cline-rules"
|
||||
import { ExtensionMessage, ExtensionState, Platform } from "@shared/ExtensionMessage"
|
||||
import { HistoryItem } from "@shared/HistoryItem"
|
||||
@@ -50,6 +50,7 @@ export class Controller {
|
||||
|
||||
private disposables: vscode.Disposable[] = []
|
||||
task?: Task
|
||||
|
||||
workspaceTracker: WorkspaceTracker
|
||||
mcpHub: McpHub
|
||||
accountService: ClineAccountService
|
||||
@@ -83,8 +84,8 @@ export class Controller {
|
||||
})
|
||||
}
|
||||
|
||||
private async getCurrentMode(): Promise<"plan" | "act"> {
|
||||
return ((await getGlobalState(this.context, "mode")) as "plan" | "act" | undefined) || "act"
|
||||
async getCurrentMode(): Promise<Mode> {
|
||||
return ((await getGlobalState(this.context, "mode")) as Mode | undefined) || "act"
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -112,7 +113,10 @@ export class Controller {
|
||||
// TODO: update to clineAccountId and then move clineApiKey to a clear function.
|
||||
await storeSecret(this.context, "clineAccountId", undefined)
|
||||
await updateGlobalState(this.context, "userInfo", undefined)
|
||||
await updateGlobalState(this.context, "apiProvider", "openrouter")
|
||||
await Promise.all([
|
||||
updateGlobalState(this.context, "planModeApiProvider", "openrouter"),
|
||||
updateGlobalState(this.context, "actModeApiProvider", "openrouter"),
|
||||
])
|
||||
await this.postStateToWebview()
|
||||
getHostBridgeProvider().windowClient.showMessage({
|
||||
type: ShowMessageType.INFORMATION,
|
||||
@@ -253,153 +257,10 @@ export class Controller {
|
||||
// Capture mode switch telemetry | Capture regardless of if we know the taskId
|
||||
telemetryService.captureModeSwitch(this.task?.taskId ?? "0", chatSettings.mode)
|
||||
|
||||
// Get previous model info that we will revert to after saving current mode api info
|
||||
const {
|
||||
apiConfiguration,
|
||||
previousModeApiProvider: newApiProvider,
|
||||
previousModeModelId: newModelId,
|
||||
previousModeModelInfo: newModelInfo,
|
||||
previousModeVsCodeLmModelSelector: newVsCodeLmModelSelector,
|
||||
previousModeThinkingBudgetTokens: newThinkingBudgetTokens,
|
||||
previousModeReasoningEffort: newReasoningEffort,
|
||||
previousModeAwsBedrockCustomSelected: newAwsBedrockCustomSelected,
|
||||
previousModeAwsBedrockCustomModelBaseId: newAwsBedrockCustomModelBaseId,
|
||||
previousModeSapAiCoreModelId: newSapAiCoreModelId,
|
||||
planActSeparateModelsSetting,
|
||||
} = await getAllExtensionState(this.context)
|
||||
|
||||
const shouldSwitchModel = planActSeparateModelsSetting === true
|
||||
|
||||
if (shouldSwitchModel) {
|
||||
// Save the last model used in this mode
|
||||
await updateGlobalState(this.context, "previousModeApiProvider", apiConfiguration.apiProvider)
|
||||
await updateGlobalState(this.context, "previousModeThinkingBudgetTokens", apiConfiguration.thinkingBudgetTokens)
|
||||
await updateGlobalState(this.context, "previousModeReasoningEffort", apiConfiguration.reasoningEffort)
|
||||
switch (apiConfiguration.apiProvider) {
|
||||
case "anthropic":
|
||||
case "vertex":
|
||||
case "gemini":
|
||||
case "asksage":
|
||||
case "openai-native":
|
||||
case "qwen":
|
||||
case "deepseek":
|
||||
case "xai":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.apiModelId)
|
||||
break
|
||||
case "bedrock":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.apiModelId)
|
||||
await updateGlobalState(
|
||||
this.context,
|
||||
"previousModeAwsBedrockCustomSelected",
|
||||
apiConfiguration.awsBedrockCustomSelected,
|
||||
)
|
||||
await updateGlobalState(
|
||||
this.context,
|
||||
"previousModeAwsBedrockCustomModelBaseId",
|
||||
apiConfiguration.awsBedrockCustomModelBaseId,
|
||||
)
|
||||
break
|
||||
case "openrouter":
|
||||
case "cline":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.openRouterModelId)
|
||||
await updateGlobalState(this.context, "previousModeModelInfo", apiConfiguration.openRouterModelInfo)
|
||||
break
|
||||
case "vscode-lm":
|
||||
// Important we don't set modelId to this, as it's an object not string (webview expects model id to be a string)
|
||||
await updateGlobalState(
|
||||
this.context,
|
||||
"previousModeVsCodeLmModelSelector",
|
||||
apiConfiguration.vsCodeLmModelSelector,
|
||||
)
|
||||
break
|
||||
case "openai":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.openAiModelId)
|
||||
await updateGlobalState(this.context, "previousModeModelInfo", apiConfiguration.openAiModelInfo)
|
||||
break
|
||||
case "ollama":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.ollamaModelId)
|
||||
break
|
||||
case "lmstudio":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.lmStudioModelId)
|
||||
break
|
||||
case "litellm":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.liteLlmModelId)
|
||||
await updateGlobalState(this.context, "previousModeModelInfo", apiConfiguration.liteLlmModelInfo)
|
||||
break
|
||||
case "requesty":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.requestyModelId)
|
||||
await updateGlobalState(this.context, "previousModeModelInfo", apiConfiguration.requestyModelInfo)
|
||||
break
|
||||
case "sapaicore":
|
||||
await updateGlobalState(this.context, "previousModeModelId", apiConfiguration.apiModelId)
|
||||
await updateGlobalState(this.context, "previousModeSapAiCoreModelId", apiConfiguration.sapAiCoreModelId)
|
||||
break
|
||||
}
|
||||
|
||||
// Restore the model used in previous mode
|
||||
if (
|
||||
newApiProvider ||
|
||||
newModelId ||
|
||||
newThinkingBudgetTokens !== undefined ||
|
||||
newReasoningEffort ||
|
||||
newVsCodeLmModelSelector
|
||||
) {
|
||||
await updateGlobalState(this.context, "apiProvider", newApiProvider)
|
||||
await updateGlobalState(this.context, "thinkingBudgetTokens", newThinkingBudgetTokens)
|
||||
await updateGlobalState(this.context, "reasoningEffort", newReasoningEffort)
|
||||
switch (newApiProvider) {
|
||||
case "anthropic":
|
||||
case "vertex":
|
||||
case "gemini":
|
||||
case "asksage":
|
||||
case "openai-native":
|
||||
case "qwen":
|
||||
case "deepseek":
|
||||
case "xai":
|
||||
await updateGlobalState(this.context, "apiModelId", newModelId)
|
||||
break
|
||||
case "bedrock":
|
||||
await updateGlobalState(this.context, "apiModelId", newModelId)
|
||||
await updateGlobalState(this.context, "awsBedrockCustomSelected", newAwsBedrockCustomSelected)
|
||||
await updateGlobalState(this.context, "awsBedrockCustomModelBaseId", newAwsBedrockCustomModelBaseId)
|
||||
break
|
||||
case "openrouter":
|
||||
case "cline":
|
||||
await updateGlobalState(this.context, "openRouterModelId", newModelId)
|
||||
await updateGlobalState(this.context, "openRouterModelInfo", newModelInfo)
|
||||
break
|
||||
case "vscode-lm":
|
||||
await updateGlobalState(this.context, "vsCodeLmModelSelector", newVsCodeLmModelSelector)
|
||||
break
|
||||
case "openai":
|
||||
await updateGlobalState(this.context, "openAiModelId", newModelId)
|
||||
await updateGlobalState(this.context, "openAiModelInfo", newModelInfo)
|
||||
break
|
||||
case "ollama":
|
||||
await updateGlobalState(this.context, "ollamaModelId", newModelId)
|
||||
break
|
||||
case "lmstudio":
|
||||
await updateGlobalState(this.context, "lmStudioModelId", newModelId)
|
||||
break
|
||||
case "litellm":
|
||||
await updateGlobalState(this.context, "liteLlmModelId", newModelId)
|
||||
await updateGlobalState(this.context, "liteLlmModelInfo", newModelInfo)
|
||||
break
|
||||
case "requesty":
|
||||
await updateGlobalState(this.context, "requestyModelId", newModelId)
|
||||
await updateGlobalState(this.context, "requestyModelInfo", newModelInfo)
|
||||
break
|
||||
case "sapaicore":
|
||||
await updateGlobalState(this.context, "apiModelId", newModelId)
|
||||
await updateGlobalState(this.context, "sapAiCoreModelId", newSapAiCoreModelId)
|
||||
break
|
||||
}
|
||||
|
||||
if (this.task) {
|
||||
const { apiConfiguration: updatedApiConfiguration } = await getAllExtensionState(this.context)
|
||||
this.task.api = buildApiHandler(updatedApiConfiguration)
|
||||
}
|
||||
}
|
||||
// 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, chatSettings.mode)
|
||||
}
|
||||
|
||||
// Save only non-mode properties to global storage
|
||||
@@ -463,19 +324,38 @@ export class Controller {
|
||||
await this.authService.handleAuthCallback(customToken, provider ? provider : "google")
|
||||
|
||||
const clineProvider: ApiProvider = "cline"
|
||||
await updateGlobalState(this.context, "apiProvider", clineProvider)
|
||||
|
||||
// Mark welcome view as completed since user has successfully logged in
|
||||
await updateGlobalState(this.context, "welcomeViewCompleted", true)
|
||||
// Get current settings to determine how to update providers
|
||||
const { planActSeparateModelsSetting } = await getAllExtensionState(this.context)
|
||||
const currentMode = await this.getCurrentMode()
|
||||
|
||||
if (planActSeparateModelsSetting) {
|
||||
// Only update the current mode's provider
|
||||
if (currentMode === "plan") {
|
||||
await updateGlobalState(this.context, "planModeApiProvider", clineProvider)
|
||||
} else {
|
||||
await updateGlobalState(this.context, "actModeApiProvider", clineProvider)
|
||||
}
|
||||
} else {
|
||||
// Update both modes to keep them in sync
|
||||
await Promise.all([
|
||||
updateGlobalState(this.context, "planModeApiProvider", clineProvider),
|
||||
updateGlobalState(this.context, "actModeApiProvider", clineProvider),
|
||||
])
|
||||
}
|
||||
|
||||
// Get the updated API configuration (now includes the updated providers)
|
||||
const { apiConfiguration } = await getAllExtensionState(this.context)
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
apiProvider: clineProvider,
|
||||
}
|
||||
|
||||
// Mark welcome view as completed since user has successfully logged in
|
||||
await updateGlobalState(this.context, "welcomeViewCompleted", true)
|
||||
|
||||
if (this.task) {
|
||||
this.task.api = buildApiHandler(updatedConfig)
|
||||
this.task.api = buildApiHandler(updatedConfig, currentMode)
|
||||
}
|
||||
|
||||
await this.postStateToWebview()
|
||||
@@ -630,14 +510,21 @@ export class Controller {
|
||||
}
|
||||
|
||||
const openrouter: ApiProvider = "openrouter"
|
||||
await updateGlobalState(this.context, "apiProvider", openrouter)
|
||||
const currentMode = await this.getCurrentMode()
|
||||
await Promise.all([
|
||||
updateGlobalState(this.context, "planModeApiProvider", openrouter),
|
||||
updateGlobalState(this.context, "actModeApiProvider", openrouter),
|
||||
])
|
||||
await storeSecret(this.context, "openRouterApiKey", apiKey)
|
||||
await this.postStateToWebview()
|
||||
if (this.task) {
|
||||
this.task.api = buildApiHandler({
|
||||
apiProvider: openrouter,
|
||||
// Get the updated API configuration (now includes the updated providers)
|
||||
const { apiConfiguration } = await getAllExtensionState(this.context)
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
openRouterApiKey: apiKey,
|
||||
})
|
||||
}
|
||||
this.task.api = buildApiHandler(updatedConfig, currentMode)
|
||||
}
|
||||
// await this.postMessageToWebview({ type: "action", action: "settingsButtonClicked" }) // bad ux if user is on welcome
|
||||
}
|
||||
@@ -1013,9 +900,10 @@ Commit message:`
|
||||
|
||||
// Get the current API configuration
|
||||
const { apiConfiguration } = await getAllExtensionState(this.context)
|
||||
const currentMode = await this.getCurrentMode()
|
||||
|
||||
// Build the API handler
|
||||
const apiHandler = buildApiHandler(apiConfiguration)
|
||||
const apiHandler = buildApiHandler(apiConfiguration, currentMode)
|
||||
|
||||
// Create a system prompt
|
||||
const systemPrompt =
|
||||
|
||||
@@ -29,7 +29,8 @@ export async function updateApiConfigurationProto(
|
||||
|
||||
// Update the task's API handler if there's an active task
|
||||
if (controller.task) {
|
||||
controller.task.api = buildApiHandler(appApiConfiguration)
|
||||
const currentMode = await controller.getCurrentMode()
|
||||
controller.task.api = buildApiHandler(appApiConfiguration, currentMode)
|
||||
}
|
||||
|
||||
// Post updated state to webview
|
||||
|
||||
@@ -21,7 +21,8 @@ export async function updateSettings(controller: Controller, request: UpdateSett
|
||||
await updateApiConfiguration(controller.context, apiConfiguration)
|
||||
|
||||
if (controller.task) {
|
||||
controller.task.api = buildApiHandler(apiConfiguration)
|
||||
const currentMode = await controller.getCurrentMode()
|
||||
controller.task.api = buildApiHandler(apiConfiguration, currentMode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,25 +30,77 @@ export async function initializeWebview(controller: Controller, request: EmptyRe
|
||||
handleModelsServiceRequest(controller, "refreshOpenRouterModels", EmptyRequest.create()).then(async (response) => {
|
||||
if (response && response.models) {
|
||||
// Update model info in state (this needs to be done here since we don't want to update state while settings is open, and we may refresh models there)
|
||||
const { apiConfiguration } = await getAllExtensionState(controller.context)
|
||||
if (apiConfiguration.openRouterModelId && response.models[apiConfiguration.openRouterModelId]) {
|
||||
await updateGlobalState(
|
||||
controller.context,
|
||||
"openRouterModelInfo",
|
||||
response.models[apiConfiguration.openRouterModelId],
|
||||
)
|
||||
await controller.postStateToWebview()
|
||||
const { apiConfiguration, planActSeparateModelsSetting } = await getAllExtensionState(controller.context)
|
||||
const currentMode = await controller.getCurrentMode()
|
||||
|
||||
if (planActSeparateModelsSetting) {
|
||||
// Separate models: update only current mode
|
||||
const modelIdField = currentMode === "plan" ? "planModeOpenRouterModelId" : "actModeOpenRouterModelId"
|
||||
const modelInfoField = currentMode === "plan" ? "planModeOpenRouterModelInfo" : "actModeOpenRouterModelInfo"
|
||||
const modelId = apiConfiguration[modelIdField]
|
||||
|
||||
if (modelId && response.models[modelId]) {
|
||||
await updateGlobalState(controller.context, modelInfoField, response.models[modelId])
|
||||
await controller.postStateToWebview()
|
||||
}
|
||||
} else {
|
||||
// Shared models: update both plan and act modes
|
||||
const planModelId = apiConfiguration.planModeOpenRouterModelId
|
||||
const actModelId = apiConfiguration.actModeOpenRouterModelId
|
||||
|
||||
// Update plan mode model info if we have a model ID
|
||||
if (planModelId && response.models[planModelId]) {
|
||||
await updateGlobalState(controller.context, "planModeOpenRouterModelInfo", response.models[planModelId])
|
||||
}
|
||||
|
||||
// Update act mode model info if we have a model ID
|
||||
if (actModelId && response.models[actModelId]) {
|
||||
await updateGlobalState(controller.context, "actModeOpenRouterModelInfo", response.models[actModelId])
|
||||
}
|
||||
|
||||
// Post state update if we updated any model info
|
||||
if ((planModelId && response.models[planModelId]) || (actModelId && response.models[actModelId])) {
|
||||
await controller.postStateToWebview()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
handleModelsServiceRequest(controller, "refreshGroqModels", EmptyRequest.create()).then(async (response) => {
|
||||
if (response && response.models) {
|
||||
// update model info in state for Groq
|
||||
const { apiConfiguration } = await getAllExtensionState(controller.context)
|
||||
if (apiConfiguration.groqModelId && response.models[apiConfiguration.groqModelId]) {
|
||||
await updateGlobalState(controller.context, "groqModelInfo", response.models[apiConfiguration.groqModelId])
|
||||
await controller.postStateToWebview()
|
||||
// Update model info in state for Groq (this needs to be done here since we don't want to update state while settings is open, and we may refresh models there)
|
||||
const { apiConfiguration, planActSeparateModelsSetting } = await getAllExtensionState(controller.context)
|
||||
const currentMode = await controller.getCurrentMode()
|
||||
|
||||
if (planActSeparateModelsSetting) {
|
||||
// Separate models: update only current mode
|
||||
const modelIdField = currentMode === "plan" ? "planModeGroqModelId" : "actModeGroqModelId"
|
||||
const modelInfoField = currentMode === "plan" ? "planModeGroqModelInfo" : "actModeGroqModelInfo"
|
||||
const modelId = apiConfiguration[modelIdField]
|
||||
|
||||
if (modelId && response.models[modelId]) {
|
||||
await updateGlobalState(controller.context, modelInfoField, response.models[modelId])
|
||||
await controller.postStateToWebview()
|
||||
}
|
||||
} else {
|
||||
// Shared models: update both plan and act modes
|
||||
const planModelId = apiConfiguration.planModeGroqModelId
|
||||
const actModelId = apiConfiguration.actModeGroqModelId
|
||||
|
||||
// Update plan mode model info if we have a model ID
|
||||
if (planModelId && response.models[planModelId]) {
|
||||
await updateGlobalState(controller.context, "planModeGroqModelInfo", response.models[planModelId])
|
||||
}
|
||||
|
||||
// Update act mode model info if we have a model ID
|
||||
if (actModelId && response.models[actModelId]) {
|
||||
await updateGlobalState(controller.context, "actModeGroqModelInfo", response.models[actModelId])
|
||||
}
|
||||
|
||||
// Post state update if we updated any model info
|
||||
if ((planModelId && response.models[planModelId]) || (actModelId && response.models[actModelId])) {
|
||||
await controller.postStateToWebview()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,6 +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"
|
||||
|
||||
export const formatResponse = {
|
||||
duplicateFileReadNotice: () =>
|
||||
@@ -147,7 +148,7 @@ Otherwise, if you have not completed the task and do not need additional informa
|
||||
},
|
||||
|
||||
taskResumption: (
|
||||
mode: "plan" | "act",
|
||||
mode: Mode,
|
||||
agoText: string,
|
||||
cwd: string,
|
||||
wasRecent: boolean | 0 | undefined,
|
||||
|
||||
@@ -43,12 +43,9 @@ export type GlobalStateKey =
|
||||
| "lastShownAnnouncementId"
|
||||
| "taskHistory"
|
||||
| "openAiBaseUrl"
|
||||
| "openAiModelId"
|
||||
| "openAiModelInfo"
|
||||
| "openAiHeaders"
|
||||
| "ollamaBaseUrl"
|
||||
| "ollamaApiOptionsCtxNum"
|
||||
| "lmStudioModelId"
|
||||
| "lmStudioBaseUrl"
|
||||
| "anthropicBaseUrl"
|
||||
| "geminiBaseUrl"
|
||||
@@ -88,40 +85,55 @@ export type GlobalStateKey =
|
||||
// Settings around plan/act and ephemeral model configuration
|
||||
| "chatSettings"
|
||||
| "mode"
|
||||
// Current active model configuration (per workspace)
|
||||
| "apiProvider"
|
||||
| "apiModelId"
|
||||
| "thinkingBudgetTokens"
|
||||
| "reasoningEffort"
|
||||
| "vsCodeLmModelSelector"
|
||||
| "awsBedrockCustomSelected"
|
||||
| "awsBedrockCustomModelBaseId"
|
||||
| "openRouterModelId"
|
||||
| "openRouterModelInfo"
|
||||
| "openAiModelId"
|
||||
| "openAiModelInfo"
|
||||
| "ollamaModelId"
|
||||
| "lmStudioModelId"
|
||||
| "liteLlmModelId"
|
||||
| "liteLlmModelInfo"
|
||||
| "requestyModelId"
|
||||
| "requestyModelInfo"
|
||||
| "togetherModelId"
|
||||
| "fireworksModelId"
|
||||
| "huggingFaceModelId"
|
||||
| "huggingFaceModelInfo"
|
||||
| "sapAiCoreModelId"
|
||||
// Previous mode saved configurations (per workspace)
|
||||
| "previousModeApiProvider"
|
||||
| "previousModeModelId"
|
||||
| "previousModeModelInfo"
|
||||
| "previousModeVsCodeLmModelSelector"
|
||||
| "previousModeThinkingBudgetTokens"
|
||||
| "previousModeReasoningEffort"
|
||||
| "previousModeAwsBedrockCustomSelected"
|
||||
| "previousModeAwsBedrockCustomModelBaseId"
|
||||
| "previousModeSapAiCoreModelId"
|
||||
| "groqModelId"
|
||||
| "groqModelInfo"
|
||||
// Plan mode configurations
|
||||
| "planModeApiProvider"
|
||||
| "planModeApiModelId"
|
||||
| "planModeThinkingBudgetTokens"
|
||||
| "planModeReasoningEffort"
|
||||
| "planModeVsCodeLmModelSelector"
|
||||
| "planModeAwsBedrockCustomSelected"
|
||||
| "planModeAwsBedrockCustomModelBaseId"
|
||||
| "planModeOpenRouterModelId"
|
||||
| "planModeOpenRouterModelInfo"
|
||||
| "planModeOpenAiModelId"
|
||||
| "planModeOpenAiModelInfo"
|
||||
| "planModeOllamaModelId"
|
||||
| "planModeLmStudioModelId"
|
||||
| "planModeLiteLlmModelId"
|
||||
| "planModeLiteLlmModelInfo"
|
||||
| "planModeRequestyModelId"
|
||||
| "planModeRequestyModelInfo"
|
||||
| "planModeTogetherModelId"
|
||||
| "planModeFireworksModelId"
|
||||
| "planModeSapAiCoreModelId"
|
||||
| "planModeGroqModelId"
|
||||
| "planModeGroqModelInfo"
|
||||
| "planModeHuggingFaceModelId"
|
||||
| "planModeHuggingFaceModelInfo"
|
||||
// Act mode configurations
|
||||
| "actModeApiProvider"
|
||||
| "actModeApiModelId"
|
||||
| "actModeThinkingBudgetTokens"
|
||||
| "actModeReasoningEffort"
|
||||
| "actModeVsCodeLmModelSelector"
|
||||
| "actModeAwsBedrockCustomSelected"
|
||||
| "actModeAwsBedrockCustomModelBaseId"
|
||||
| "actModeOpenRouterModelId"
|
||||
| "actModeOpenRouterModelInfo"
|
||||
| "actModeOpenAiModelId"
|
||||
| "actModeOpenAiModelInfo"
|
||||
| "actModeOllamaModelId"
|
||||
| "actModeLmStudioModelId"
|
||||
| "actModeLiteLlmModelId"
|
||||
| "actModeLiteLlmModelInfo"
|
||||
| "actModeRequestyModelId"
|
||||
| "actModeRequestyModelInfo"
|
||||
| "actModeTogetherModelId"
|
||||
| "actModeFireworksModelId"
|
||||
| "actModeSapAiCoreModelId"
|
||||
| "actModeGroqModelId"
|
||||
| "actModeGroqModelInfo"
|
||||
| "actModeHuggingFaceModelId"
|
||||
| "actModeHuggingFaceModelInfo"
|
||||
|
||||
export type LocalStateKey = "localClineRulesToggles" | "localCursorRulesToggles" | "localWindsurfRulesToggles" | "workflowToggles"
|
||||
|
||||
@@ -32,6 +32,10 @@ export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionC
|
||||
"togetherModelId",
|
||||
"fireworksModelId",
|
||||
"sapAiCoreModelId",
|
||||
"groqModelId",
|
||||
"groqModelInfo",
|
||||
"huggingFaceModelId",
|
||||
"huggingFaceModelInfo",
|
||||
|
||||
// Previous mode settings
|
||||
"previousModeApiProvider",
|
||||
@@ -53,8 +57,8 @@ export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionC
|
||||
if (workspaceValue !== undefined && globalValue === undefined) {
|
||||
console.log(`[Storage Migration] migrating key: ${key} to global storage. Current value: ${workspaceValue}`)
|
||||
|
||||
// Move to global storage
|
||||
await updateGlobalState(context, key as GlobalStateKey, workspaceValue)
|
||||
// Move to global storage using raw VSCode method to avoid type errors
|
||||
await context.globalState.update(key, workspaceValue)
|
||||
// Remove from workspace storage
|
||||
await context.workspaceState.update(key, undefined)
|
||||
const newWorkspaceValue = await context.workspaceState.get(key)
|
||||
@@ -169,6 +173,375 @@ export async function migrateModeFromWorkspaceStorageToControllerState(context:
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateLegacyApiConfigurationToModeSpecific(context: vscode.ExtensionContext) {
|
||||
try {
|
||||
// Check if migration is needed - if planModeApiProvider already exists, skip migration
|
||||
const planModeApiProvider = await context.globalState.get("planModeApiProvider")
|
||||
if (planModeApiProvider !== undefined) {
|
||||
console.log("Legacy API configuration migration already completed, skipping...")
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Starting legacy API configuration migration to mode-specific keys...")
|
||||
|
||||
// Get the planActSeparateModelsSetting to determine migration strategy
|
||||
const planActSeparateModelsSetting = (await context.globalState.get("planActSeparateModelsSetting")) as
|
||||
| boolean
|
||||
| undefined
|
||||
|
||||
// Read legacy values directly
|
||||
const apiProvider = await context.globalState.get("apiProvider")
|
||||
const apiModelId = await context.globalState.get("apiModelId")
|
||||
const thinkingBudgetTokens = await context.globalState.get("thinkingBudgetTokens")
|
||||
const reasoningEffort = await context.globalState.get("reasoningEffort")
|
||||
const vsCodeLmModelSelector = await context.globalState.get("vsCodeLmModelSelector")
|
||||
const awsBedrockCustomSelected = await context.globalState.get("awsBedrockCustomSelected")
|
||||
const awsBedrockCustomModelBaseId = await context.globalState.get("awsBedrockCustomModelBaseId")
|
||||
const openRouterModelId = await context.globalState.get("openRouterModelId")
|
||||
const openRouterModelInfo = await context.globalState.get("openRouterModelInfo")
|
||||
const openAiModelId = await context.globalState.get("openAiModelId")
|
||||
const openAiModelInfo = await context.globalState.get("openAiModelInfo")
|
||||
const ollamaModelId = await context.globalState.get("ollamaModelId")
|
||||
const lmStudioModelId = await context.globalState.get("lmStudioModelId")
|
||||
const liteLlmModelId = await context.globalState.get("liteLlmModelId")
|
||||
const liteLlmModelInfo = await context.globalState.get("liteLlmModelInfo")
|
||||
const requestyModelId = await context.globalState.get("requestyModelId")
|
||||
const requestyModelInfo = await context.globalState.get("requestyModelInfo")
|
||||
const togetherModelId = await context.globalState.get("togetherModelId")
|
||||
const fireworksModelId = await context.globalState.get("fireworksModelId")
|
||||
const sapAiCoreModelId = await context.globalState.get("sapAiCoreModelId")
|
||||
const groqModelId = await context.globalState.get("groqModelId")
|
||||
const groqModelInfo = await context.globalState.get("groqModelInfo")
|
||||
const huggingFaceModelId = await context.globalState.get("huggingFaceModelId")
|
||||
const huggingFaceModelInfo = await context.globalState.get("huggingFaceModelInfo")
|
||||
|
||||
// Read previous mode values
|
||||
const previousModeApiProvider = await context.globalState.get("previousModeApiProvider")
|
||||
const previousModeModelId = await context.globalState.get("previousModeModelId")
|
||||
const previousModeModelInfo = await context.globalState.get("previousModeModelInfo")
|
||||
const previousModeVsCodeLmModelSelector = await context.globalState.get("previousModeVsCodeLmModelSelector")
|
||||
const previousModeThinkingBudgetTokens = await context.globalState.get("previousModeThinkingBudgetTokens")
|
||||
const previousModeReasoningEffort = await context.globalState.get("previousModeReasoningEffort")
|
||||
const previousModeAwsBedrockCustomSelected = await context.globalState.get("previousModeAwsBedrockCustomSelected")
|
||||
const previousModeAwsBedrockCustomModelBaseId = await context.globalState.get("previousModeAwsBedrockCustomModelBaseId")
|
||||
const previousModeSapAiCoreModelId = await context.globalState.get("previousModeSapAiCoreModelId")
|
||||
|
||||
// Migrate based on planActSeparateModelsSetting
|
||||
if (planActSeparateModelsSetting === false) {
|
||||
console.log("Migrating with separate models DISABLED - using current values for both modes")
|
||||
|
||||
// Use current values for both plan and act modes
|
||||
if (apiProvider !== undefined) {
|
||||
await context.globalState.update("planModeApiProvider", apiProvider)
|
||||
await context.globalState.update("actModeApiProvider", apiProvider)
|
||||
}
|
||||
if (apiModelId !== undefined) {
|
||||
await context.globalState.update("planModeApiModelId", apiModelId)
|
||||
await context.globalState.update("actModeApiModelId", apiModelId)
|
||||
}
|
||||
if (thinkingBudgetTokens !== undefined) {
|
||||
await context.globalState.update("planModeThinkingBudgetTokens", thinkingBudgetTokens)
|
||||
await context.globalState.update("actModeThinkingBudgetTokens", thinkingBudgetTokens)
|
||||
}
|
||||
if (reasoningEffort !== undefined) {
|
||||
await context.globalState.update("planModeReasoningEffort", reasoningEffort)
|
||||
await context.globalState.update("actModeReasoningEffort", reasoningEffort)
|
||||
}
|
||||
if (vsCodeLmModelSelector !== undefined) {
|
||||
await context.globalState.update("planModeVsCodeLmModelSelector", vsCodeLmModelSelector)
|
||||
await context.globalState.update("actModeVsCodeLmModelSelector", vsCodeLmModelSelector)
|
||||
}
|
||||
if (awsBedrockCustomSelected !== undefined) {
|
||||
await context.globalState.update("planModeAwsBedrockCustomSelected", awsBedrockCustomSelected)
|
||||
await context.globalState.update("actModeAwsBedrockCustomSelected", awsBedrockCustomSelected)
|
||||
}
|
||||
if (awsBedrockCustomModelBaseId !== undefined) {
|
||||
await context.globalState.update("planModeAwsBedrockCustomModelBaseId", awsBedrockCustomModelBaseId)
|
||||
await context.globalState.update("actModeAwsBedrockCustomModelBaseId", awsBedrockCustomModelBaseId)
|
||||
}
|
||||
if (openRouterModelId !== undefined) {
|
||||
await context.globalState.update("planModeOpenRouterModelId", openRouterModelId)
|
||||
await context.globalState.update("actModeOpenRouterModelId", openRouterModelId)
|
||||
}
|
||||
if (openRouterModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeOpenRouterModelInfo", openRouterModelInfo)
|
||||
await context.globalState.update("actModeOpenRouterModelInfo", openRouterModelInfo)
|
||||
}
|
||||
if (openAiModelId !== undefined) {
|
||||
await context.globalState.update("planModeOpenAiModelId", openAiModelId)
|
||||
await context.globalState.update("actModeOpenAiModelId", openAiModelId)
|
||||
}
|
||||
if (openAiModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeOpenAiModelInfo", openAiModelInfo)
|
||||
await context.globalState.update("actModeOpenAiModelInfo", openAiModelInfo)
|
||||
}
|
||||
if (ollamaModelId !== undefined) {
|
||||
await context.globalState.update("planModeOllamaModelId", ollamaModelId)
|
||||
await context.globalState.update("actModeOllamaModelId", ollamaModelId)
|
||||
}
|
||||
if (lmStudioModelId !== undefined) {
|
||||
await context.globalState.update("planModeLmStudioModelId", lmStudioModelId)
|
||||
await context.globalState.update("actModeLmStudioModelId", lmStudioModelId)
|
||||
}
|
||||
if (liteLlmModelId !== undefined) {
|
||||
await context.globalState.update("planModeLiteLlmModelId", liteLlmModelId)
|
||||
await context.globalState.update("actModeLiteLlmModelId", liteLlmModelId)
|
||||
}
|
||||
if (liteLlmModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeLiteLlmModelInfo", liteLlmModelInfo)
|
||||
await context.globalState.update("actModeLiteLlmModelInfo", liteLlmModelInfo)
|
||||
}
|
||||
if (requestyModelId !== undefined) {
|
||||
await context.globalState.update("planModeRequestyModelId", requestyModelId)
|
||||
await context.globalState.update("actModeRequestyModelId", requestyModelId)
|
||||
}
|
||||
if (requestyModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeRequestyModelInfo", requestyModelInfo)
|
||||
await context.globalState.update("actModeRequestyModelInfo", requestyModelInfo)
|
||||
}
|
||||
if (togetherModelId !== undefined) {
|
||||
await context.globalState.update("planModeTogetherModelId", togetherModelId)
|
||||
await context.globalState.update("actModeTogetherModelId", togetherModelId)
|
||||
}
|
||||
if (fireworksModelId !== undefined) {
|
||||
await context.globalState.update("planModeFireworksModelId", fireworksModelId)
|
||||
await context.globalState.update("actModeFireworksModelId", fireworksModelId)
|
||||
}
|
||||
if (sapAiCoreModelId !== undefined) {
|
||||
await context.globalState.update("planModeSapAiCoreModelId", sapAiCoreModelId)
|
||||
await context.globalState.update("actModeSapAiCoreModelId", sapAiCoreModelId)
|
||||
}
|
||||
if (groqModelId !== undefined) {
|
||||
await context.globalState.update("planModeGroqModelId", groqModelId)
|
||||
await context.globalState.update("actModeGroqModelId", groqModelId)
|
||||
}
|
||||
if (groqModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeGroqModelInfo", groqModelInfo)
|
||||
await context.globalState.update("actModeGroqModelInfo", groqModelInfo)
|
||||
}
|
||||
if (huggingFaceModelId !== undefined) {
|
||||
await context.globalState.update("planModeHuggingFaceModelId", huggingFaceModelId)
|
||||
await context.globalState.update("actModeHuggingFaceModelId", huggingFaceModelId)
|
||||
}
|
||||
if (huggingFaceModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeHuggingFaceModelInfo", huggingFaceModelInfo)
|
||||
await context.globalState.update("actModeHuggingFaceModelInfo", huggingFaceModelInfo)
|
||||
}
|
||||
} else {
|
||||
console.log("Migrating with separate models ENABLED - using current->plan, previous->act")
|
||||
|
||||
// Use current values for plan mode
|
||||
if (apiProvider !== undefined) {
|
||||
await context.globalState.update("planModeApiProvider", apiProvider)
|
||||
}
|
||||
if (apiModelId !== undefined) {
|
||||
await context.globalState.update("planModeApiModelId", apiModelId)
|
||||
}
|
||||
if (thinkingBudgetTokens !== undefined) {
|
||||
await context.globalState.update("planModeThinkingBudgetTokens", thinkingBudgetTokens)
|
||||
}
|
||||
if (reasoningEffort !== undefined) {
|
||||
await context.globalState.update("planModeReasoningEffort", reasoningEffort)
|
||||
}
|
||||
if (vsCodeLmModelSelector !== undefined) {
|
||||
await context.globalState.update("planModeVsCodeLmModelSelector", vsCodeLmModelSelector)
|
||||
}
|
||||
if (awsBedrockCustomSelected !== undefined) {
|
||||
await context.globalState.update("planModeAwsBedrockCustomSelected", awsBedrockCustomSelected)
|
||||
}
|
||||
if (awsBedrockCustomModelBaseId !== undefined) {
|
||||
await context.globalState.update("planModeAwsBedrockCustomModelBaseId", awsBedrockCustomModelBaseId)
|
||||
}
|
||||
if (openRouterModelId !== undefined) {
|
||||
await context.globalState.update("planModeOpenRouterModelId", openRouterModelId)
|
||||
}
|
||||
if (openRouterModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeOpenRouterModelInfo", openRouterModelInfo)
|
||||
}
|
||||
if (openAiModelId !== undefined) {
|
||||
await context.globalState.update("planModeOpenAiModelId", openAiModelId)
|
||||
}
|
||||
if (openAiModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeOpenAiModelInfo", openAiModelInfo)
|
||||
}
|
||||
if (ollamaModelId !== undefined) {
|
||||
await context.globalState.update("planModeOllamaModelId", ollamaModelId)
|
||||
}
|
||||
if (lmStudioModelId !== undefined) {
|
||||
await context.globalState.update("planModeLmStudioModelId", lmStudioModelId)
|
||||
}
|
||||
if (liteLlmModelId !== undefined) {
|
||||
await context.globalState.update("planModeLiteLlmModelId", liteLlmModelId)
|
||||
}
|
||||
if (liteLlmModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeLiteLlmModelInfo", liteLlmModelInfo)
|
||||
}
|
||||
if (requestyModelId !== undefined) {
|
||||
await context.globalState.update("planModeRequestyModelId", requestyModelId)
|
||||
}
|
||||
if (requestyModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeRequestyModelInfo", requestyModelInfo)
|
||||
}
|
||||
if (togetherModelId !== undefined) {
|
||||
await context.globalState.update("planModeTogetherModelId", togetherModelId)
|
||||
}
|
||||
if (fireworksModelId !== undefined) {
|
||||
await context.globalState.update("planModeFireworksModelId", fireworksModelId)
|
||||
}
|
||||
if (sapAiCoreModelId !== undefined) {
|
||||
await context.globalState.update("planModeSapAiCoreModelId", sapAiCoreModelId)
|
||||
}
|
||||
if (groqModelId !== undefined) {
|
||||
await context.globalState.update("planModeGroqModelId", groqModelId)
|
||||
}
|
||||
if (groqModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeGroqModelInfo", groqModelInfo)
|
||||
}
|
||||
if (huggingFaceModelId !== undefined) {
|
||||
await context.globalState.update("planModeHuggingFaceModelId", huggingFaceModelId)
|
||||
}
|
||||
if (huggingFaceModelInfo !== undefined) {
|
||||
await context.globalState.update("planModeHuggingFaceModelInfo", huggingFaceModelInfo)
|
||||
}
|
||||
|
||||
// Use previous values for act mode (with fallback to current values)
|
||||
if (previousModeApiProvider !== undefined) {
|
||||
await context.globalState.update("actModeApiProvider", previousModeApiProvider)
|
||||
} else if (apiProvider !== undefined) {
|
||||
await context.globalState.update("actModeApiProvider", apiProvider)
|
||||
}
|
||||
if (previousModeModelId !== undefined) {
|
||||
await context.globalState.update("actModeApiModelId", previousModeModelId)
|
||||
} else if (apiModelId !== undefined) {
|
||||
await context.globalState.update("actModeApiModelId", apiModelId)
|
||||
}
|
||||
if (previousModeThinkingBudgetTokens !== undefined) {
|
||||
await context.globalState.update("actModeThinkingBudgetTokens", previousModeThinkingBudgetTokens)
|
||||
} else if (thinkingBudgetTokens !== undefined) {
|
||||
await context.globalState.update("actModeThinkingBudgetTokens", thinkingBudgetTokens)
|
||||
}
|
||||
if (previousModeReasoningEffort !== undefined) {
|
||||
await context.globalState.update("actModeReasoningEffort", previousModeReasoningEffort)
|
||||
} else if (reasoningEffort !== undefined) {
|
||||
await context.globalState.update("actModeReasoningEffort", reasoningEffort)
|
||||
}
|
||||
if (previousModeVsCodeLmModelSelector !== undefined) {
|
||||
await context.globalState.update("actModeVsCodeLmModelSelector", previousModeVsCodeLmModelSelector)
|
||||
} else if (vsCodeLmModelSelector !== undefined) {
|
||||
await context.globalState.update("actModeVsCodeLmModelSelector", vsCodeLmModelSelector)
|
||||
}
|
||||
if (previousModeAwsBedrockCustomSelected !== undefined) {
|
||||
await context.globalState.update("actModeAwsBedrockCustomSelected", previousModeAwsBedrockCustomSelected)
|
||||
} else if (awsBedrockCustomSelected !== undefined) {
|
||||
await context.globalState.update("actModeAwsBedrockCustomSelected", awsBedrockCustomSelected)
|
||||
}
|
||||
if (previousModeAwsBedrockCustomModelBaseId !== undefined) {
|
||||
await context.globalState.update("actModeAwsBedrockCustomModelBaseId", previousModeAwsBedrockCustomModelBaseId)
|
||||
} else if (awsBedrockCustomModelBaseId !== undefined) {
|
||||
await context.globalState.update("actModeAwsBedrockCustomModelBaseId", awsBedrockCustomModelBaseId)
|
||||
}
|
||||
if (previousModeSapAiCoreModelId !== undefined) {
|
||||
await context.globalState.update("actModeSapAiCoreModelId", previousModeSapAiCoreModelId)
|
||||
} else if (sapAiCoreModelId !== undefined) {
|
||||
await context.globalState.update("actModeSapAiCoreModelId", sapAiCoreModelId)
|
||||
}
|
||||
|
||||
// For fields without previous variants, use current values for act mode
|
||||
if (previousModeModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeOpenRouterModelInfo", previousModeModelInfo)
|
||||
} else if (openRouterModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeOpenRouterModelInfo", openRouterModelInfo)
|
||||
}
|
||||
if (openRouterModelId !== undefined) {
|
||||
await context.globalState.update("actModeOpenRouterModelId", openRouterModelId)
|
||||
}
|
||||
if (openAiModelId !== undefined) {
|
||||
await context.globalState.update("actModeOpenAiModelId", openAiModelId)
|
||||
}
|
||||
if (openAiModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeOpenAiModelInfo", openAiModelInfo)
|
||||
}
|
||||
if (ollamaModelId !== undefined) {
|
||||
await context.globalState.update("actModeOllamaModelId", ollamaModelId)
|
||||
}
|
||||
if (lmStudioModelId !== undefined) {
|
||||
await context.globalState.update("actModeLmStudioModelId", lmStudioModelId)
|
||||
}
|
||||
if (liteLlmModelId !== undefined) {
|
||||
await context.globalState.update("actModeLiteLlmModelId", liteLlmModelId)
|
||||
}
|
||||
if (liteLlmModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeLiteLlmModelInfo", liteLlmModelInfo)
|
||||
}
|
||||
if (requestyModelId !== undefined) {
|
||||
await context.globalState.update("actModeRequestyModelId", requestyModelId)
|
||||
}
|
||||
if (requestyModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeRequestyModelInfo", requestyModelInfo)
|
||||
}
|
||||
if (togetherModelId !== undefined) {
|
||||
await context.globalState.update("actModeTogetherModelId", togetherModelId)
|
||||
}
|
||||
if (fireworksModelId !== undefined) {
|
||||
await context.globalState.update("actModeFireworksModelId", fireworksModelId)
|
||||
}
|
||||
if (groqModelId !== undefined) {
|
||||
await context.globalState.update("actModeGroqModelId", groqModelId)
|
||||
}
|
||||
if (groqModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeGroqModelInfo", groqModelInfo)
|
||||
}
|
||||
if (huggingFaceModelId !== undefined) {
|
||||
await context.globalState.update("actModeHuggingFaceModelId", huggingFaceModelId)
|
||||
}
|
||||
if (huggingFaceModelInfo !== undefined) {
|
||||
await context.globalState.update("actModeHuggingFaceModelInfo", huggingFaceModelInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up legacy keys after successful migration
|
||||
console.log("Cleaning up legacy keys...")
|
||||
await context.globalState.update("apiProvider", undefined)
|
||||
await context.globalState.update("apiModelId", undefined)
|
||||
await context.globalState.update("thinkingBudgetTokens", undefined)
|
||||
await context.globalState.update("reasoningEffort", undefined)
|
||||
await context.globalState.update("vsCodeLmModelSelector", undefined)
|
||||
await context.globalState.update("awsBedrockCustomSelected", undefined)
|
||||
await context.globalState.update("awsBedrockCustomModelBaseId", undefined)
|
||||
await context.globalState.update("openRouterModelId", undefined)
|
||||
await context.globalState.update("openRouterModelInfo", undefined)
|
||||
await context.globalState.update("openAiModelId", undefined)
|
||||
await context.globalState.update("openAiModelInfo", undefined)
|
||||
await context.globalState.update("ollamaModelId", undefined)
|
||||
await context.globalState.update("lmStudioModelId", undefined)
|
||||
await context.globalState.update("liteLlmModelId", undefined)
|
||||
await context.globalState.update("liteLlmModelInfo", undefined)
|
||||
await context.globalState.update("requestyModelId", undefined)
|
||||
await context.globalState.update("requestyModelInfo", undefined)
|
||||
await context.globalState.update("togetherModelId", undefined)
|
||||
await context.globalState.update("fireworksModelId", undefined)
|
||||
await context.globalState.update("sapAiCoreModelId", undefined)
|
||||
await context.globalState.update("groqModelId", undefined)
|
||||
await context.globalState.update("groqModelInfo", undefined)
|
||||
await context.globalState.update("huggingFaceModelId", undefined)
|
||||
await context.globalState.update("huggingFaceModelInfo", undefined)
|
||||
await context.globalState.update("previousModeApiProvider", undefined)
|
||||
await context.globalState.update("previousModeModelId", undefined)
|
||||
await context.globalState.update("previousModeModelInfo", undefined)
|
||||
await context.globalState.update("previousModeVsCodeLmModelSelector", undefined)
|
||||
await context.globalState.update("previousModeThinkingBudgetTokens", undefined)
|
||||
await context.globalState.update("previousModeReasoningEffort", undefined)
|
||||
await context.globalState.update("previousModeAwsBedrockCustomSelected", undefined)
|
||||
await context.globalState.update("previousModeAwsBedrockCustomModelBaseId", undefined)
|
||||
await context.globalState.update("previousModeSapAiCoreModelId", undefined)
|
||||
|
||||
console.log("Successfully migrated legacy API configuration to mode-specific keys")
|
||||
} catch (error) {
|
||||
console.error("Failed to migrate legacy API configuration to mode-specific keys:", error)
|
||||
// Continue execution - migration failure shouldn't break extension startup
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateWelcomeViewCompleted(context: vscode.ExtensionContext) {
|
||||
try {
|
||||
// Check if welcomeViewCompleted is already set
|
||||
@@ -190,8 +563,10 @@ export async function migrateWelcomeViewCompleted(context: vscode.ExtensionConte
|
||||
config.awsRegion,
|
||||
config.vertexProjectId,
|
||||
config.openAiApiKey,
|
||||
config.ollamaModelId,
|
||||
config.lmStudioModelId,
|
||||
config.planModeOllamaModelId,
|
||||
config.planModeLmStudioModelId,
|
||||
config.actModeOllamaModelId,
|
||||
config.actModeLmStudioModelId,
|
||||
config.liteLlmApiKey,
|
||||
config.geminiApiKey,
|
||||
config.openAiNativeApiKey,
|
||||
@@ -201,7 +576,8 @@ export async function migrateWelcomeViewCompleted(context: vscode.ExtensionConte
|
||||
config.qwenApiKey,
|
||||
config.doubaoApiKey,
|
||||
config.mistralApiKey,
|
||||
config.vsCodeLmModelSelector,
|
||||
config.planModeVsCodeLmModelSelector,
|
||||
config.actModeVsCodeLmModelSelector,
|
||||
config.clineAccountId,
|
||||
config.asksageApiKey,
|
||||
config.xaiApiKey,
|
||||
|
||||
+254
-154
@@ -1,5 +1,5 @@
|
||||
import * as vscode from "vscode"
|
||||
import { DEFAULT_CHAT_SETTINGS } from "@shared/ChatSettings"
|
||||
import { DEFAULT_CHAT_SETTINGS, Mode } from "@shared/ChatSettings"
|
||||
import { DEFAULT_BROWSER_SETTINGS } from "@shared/BrowserSettings"
|
||||
import { DEFAULT_AUTO_APPROVAL_SETTINGS } from "@shared/AutoApprovalSettings"
|
||||
import { GlobalStateKey, LocalStateKey, SecretKey } from "./state-keys"
|
||||
@@ -190,8 +190,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
sapAiCoreTokenUrl,
|
||||
sapAiResourceGroup,
|
||||
claudeCodePath,
|
||||
groqModelId,
|
||||
groqModelInfo,
|
||||
] = await Promise.all([
|
||||
getGlobalState(context, "isNewUser") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "welcomeViewCompleted") as Promise<boolean | undefined>,
|
||||
@@ -271,8 +269,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
getGlobalState(context, "sapAiCoreTokenUrl") as Promise<string | undefined>,
|
||||
getGlobalState(context, "sapAiResourceGroup") as Promise<string | undefined>,
|
||||
getGlobalState(context, "claudeCodePath") as Promise<string | undefined>,
|
||||
getGlobalState(context, "groqModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "groqModelInfo") as Promise<ModelInfo | undefined>,
|
||||
])
|
||||
|
||||
const localClineRulesToggles = (await getWorkspaceState(context, "localClineRulesToggles")) as ClineRulesToggles
|
||||
@@ -281,78 +277,115 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
const [
|
||||
chatSettings,
|
||||
currentMode,
|
||||
storedApiProvider,
|
||||
apiModelId,
|
||||
thinkingBudgetTokens,
|
||||
reasoningEffort,
|
||||
vsCodeLmModelSelector,
|
||||
awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openAiModelId,
|
||||
openAiModelInfo,
|
||||
ollamaModelId,
|
||||
lmStudioModelId,
|
||||
liteLlmModelId,
|
||||
liteLlmModelInfo,
|
||||
requestyModelId,
|
||||
requestyModelInfo,
|
||||
togetherModelId,
|
||||
fireworksModelId,
|
||||
previousModeApiProvider,
|
||||
previousModeModelId,
|
||||
previousModeModelInfo,
|
||||
previousModeVsCodeLmModelSelector,
|
||||
previousModeThinkingBudgetTokens,
|
||||
previousModeReasoningEffort,
|
||||
previousModeAwsBedrockCustomSelected,
|
||||
previousModeAwsBedrockCustomModelBaseId,
|
||||
previousModeSapAiCoreModelId,
|
||||
sapAiCoreModelId,
|
||||
huggingFaceModelId,
|
||||
huggingFaceModelInfo,
|
||||
// Plan mode configurations
|
||||
planModeApiProvider,
|
||||
planModeApiModelId,
|
||||
planModeThinkingBudgetTokens,
|
||||
planModeReasoningEffort,
|
||||
planModeVsCodeLmModelSelector,
|
||||
planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId,
|
||||
planModeOpenRouterModelId,
|
||||
planModeOpenRouterModelInfo,
|
||||
planModeOpenAiModelId,
|
||||
planModeOpenAiModelInfo,
|
||||
planModeOllamaModelId,
|
||||
planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo,
|
||||
planModeRequestyModelId,
|
||||
planModeRequestyModelInfo,
|
||||
planModeTogetherModelId,
|
||||
planModeFireworksModelId,
|
||||
planModeSapAiCoreModelId,
|
||||
planModeGroqModelId,
|
||||
planModeGroqModelInfo,
|
||||
planModeHuggingFaceModelId,
|
||||
planModeHuggingFaceModelInfo,
|
||||
// Act mode configurations
|
||||
actModeApiProvider,
|
||||
actModeApiModelId,
|
||||
actModeThinkingBudgetTokens,
|
||||
actModeReasoningEffort,
|
||||
actModeVsCodeLmModelSelector,
|
||||
actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId,
|
||||
actModeOpenRouterModelId,
|
||||
actModeOpenRouterModelInfo,
|
||||
actModeOpenAiModelId,
|
||||
actModeOpenAiModelInfo,
|
||||
actModeOllamaModelId,
|
||||
actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo,
|
||||
actModeRequestyModelId,
|
||||
actModeRequestyModelInfo,
|
||||
actModeTogetherModelId,
|
||||
actModeFireworksModelId,
|
||||
actModeSapAiCoreModelId,
|
||||
actModeGroqModelId,
|
||||
actModeGroqModelInfo,
|
||||
actModeHuggingFaceModelId,
|
||||
actModeHuggingFaceModelInfo,
|
||||
] = await Promise.all([
|
||||
getGlobalState(context, "chatSettings") as Promise<StoredChatSettings | undefined>,
|
||||
getGlobalState(context, "mode") as Promise<"plan" | "act" | undefined>,
|
||||
getGlobalState(context, "apiProvider") as Promise<ApiProvider | undefined>,
|
||||
getGlobalState(context, "apiModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "thinkingBudgetTokens") as Promise<number | undefined>,
|
||||
getGlobalState(context, "reasoningEffort") as Promise<string | undefined>,
|
||||
getGlobalState(context, "vsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
||||
getGlobalState(context, "awsBedrockCustomSelected") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "awsBedrockCustomModelBaseId") as Promise<BedrockModelId | undefined>,
|
||||
getGlobalState(context, "openRouterModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "openRouterModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "openAiModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "openAiModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "ollamaModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "lmStudioModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "liteLlmModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "liteLlmModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "requestyModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "requestyModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "togetherModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "fireworksModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "previousModeApiProvider") as Promise<ApiProvider | undefined>,
|
||||
getGlobalState(context, "previousModeModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "previousModeModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "previousModeVsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
||||
getGlobalState(context, "previousModeThinkingBudgetTokens") as Promise<number | undefined>,
|
||||
getGlobalState(context, "previousModeReasoningEffort") as Promise<string | undefined>,
|
||||
getGlobalState(context, "previousModeAwsBedrockCustomSelected") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "previousModeAwsBedrockCustomModelBaseId") as Promise<BedrockModelId | undefined>,
|
||||
getGlobalState(context, "previousModeSapAiCoreModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "sapAiCoreModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "huggingFaceModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "huggingFaceModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "mode") as Promise<Mode | undefined>,
|
||||
// Plan mode configurations
|
||||
getGlobalState(context, "planModeApiProvider") as Promise<ApiProvider | undefined>,
|
||||
getGlobalState(context, "planModeApiModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeThinkingBudgetTokens") as Promise<number | undefined>,
|
||||
getGlobalState(context, "planModeReasoningEffort") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeVsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
||||
getGlobalState(context, "planModeAwsBedrockCustomSelected") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "planModeAwsBedrockCustomModelBaseId") as Promise<BedrockModelId | undefined>,
|
||||
getGlobalState(context, "planModeOpenRouterModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeOpenRouterModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "planModeOpenAiModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeOpenAiModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "planModeOllamaModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeLmStudioModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeLiteLlmModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeLiteLlmModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "planModeRequestyModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeRequestyModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "planModeTogetherModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeFireworksModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeSapAiCoreModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeGroqModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeGroqModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "planModeHuggingFaceModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "planModeHuggingFaceModelInfo") as Promise<ModelInfo | undefined>,
|
||||
// Act mode configurations
|
||||
getGlobalState(context, "actModeApiProvider") as Promise<ApiProvider | undefined>,
|
||||
getGlobalState(context, "actModeApiModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeThinkingBudgetTokens") as Promise<number | undefined>,
|
||||
getGlobalState(context, "actModeReasoningEffort") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeVsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
||||
getGlobalState(context, "actModeAwsBedrockCustomSelected") as Promise<boolean | undefined>,
|
||||
getGlobalState(context, "actModeAwsBedrockCustomModelBaseId") as Promise<BedrockModelId | undefined>,
|
||||
getGlobalState(context, "actModeOpenRouterModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeOpenRouterModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "actModeOpenAiModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeOpenAiModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "actModeOllamaModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeLmStudioModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeLiteLlmModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeLiteLlmModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "actModeRequestyModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeRequestyModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "actModeTogetherModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeFireworksModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeSapAiCoreModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeGroqModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeGroqModelInfo") as Promise<ModelInfo | undefined>,
|
||||
getGlobalState(context, "actModeHuggingFaceModelId") as Promise<string | undefined>,
|
||||
getGlobalState(context, "actModeHuggingFaceModelInfo") as Promise<ModelInfo | undefined>,
|
||||
])
|
||||
|
||||
const processingStart = performance.now()
|
||||
let apiProvider: ApiProvider
|
||||
if (storedApiProvider) {
|
||||
// Use the explicitly stored provider - this respects user's selection
|
||||
apiProvider = storedApiProvider
|
||||
if (planModeApiProvider) {
|
||||
apiProvider = planModeApiProvider
|
||||
} 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)
|
||||
@@ -375,7 +408,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
planActSeparateModelsSetting = planActSeparateModelsSettingRaw
|
||||
} else {
|
||||
// default to true for existing users
|
||||
if (storedApiProvider) {
|
||||
if (planModeApiProvider) {
|
||||
planActSeparateModelsSetting = true
|
||||
} else {
|
||||
// default to false for new users
|
||||
@@ -388,8 +421,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
|
||||
return {
|
||||
apiConfiguration: {
|
||||
apiProvider,
|
||||
apiModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
clineAccountId,
|
||||
@@ -405,19 +436,13 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
awsBedrockApiKey,
|
||||
awsUseProfile,
|
||||
awsAuthentication,
|
||||
awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId,
|
||||
vertexProjectId,
|
||||
vertexRegion,
|
||||
openAiBaseUrl,
|
||||
openAiApiKey,
|
||||
openAiModelId,
|
||||
openAiModelInfo,
|
||||
openAiHeaders: openAiHeaders || {},
|
||||
ollamaModelId,
|
||||
ollamaBaseUrl,
|
||||
ollamaApiOptionsCtxNum,
|
||||
lmStudioModelId,
|
||||
lmStudioBaseUrl,
|
||||
anthropicBaseUrl,
|
||||
geminiApiKey,
|
||||
@@ -425,29 +450,18 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
openAiNativeApiKey,
|
||||
deepSeekApiKey,
|
||||
requestyApiKey,
|
||||
requestyModelId,
|
||||
requestyModelInfo,
|
||||
togetherApiKey,
|
||||
togetherModelId,
|
||||
qwenApiKey,
|
||||
qwenApiLine,
|
||||
moonshotApiLine,
|
||||
doubaoApiKey,
|
||||
mistralApiKey,
|
||||
azureApiVersion,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openRouterProviderSorting,
|
||||
vsCodeLmModelSelector,
|
||||
thinkingBudgetTokens,
|
||||
reasoningEffort,
|
||||
liteLlmBaseUrl,
|
||||
liteLlmModelId,
|
||||
liteLlmModelInfo,
|
||||
liteLlmApiKey,
|
||||
liteLlmUsePromptCache,
|
||||
fireworksApiKey,
|
||||
fireworksModelId,
|
||||
fireworksModelMaxCompletionTokens,
|
||||
fireworksModelMaxTokens,
|
||||
asksageApiKey,
|
||||
@@ -456,8 +470,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
sambanovaApiKey,
|
||||
cerebrasApiKey,
|
||||
groqApiKey,
|
||||
groqModelId,
|
||||
groqModelInfo,
|
||||
moonshotApiKey,
|
||||
nebiusApiKey,
|
||||
favoritedModelIds,
|
||||
@@ -467,10 +479,55 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
sapAiCoreBaseUrl,
|
||||
sapAiCoreTokenUrl,
|
||||
sapAiResourceGroup,
|
||||
sapAiCoreModelId,
|
||||
huggingFaceApiKey,
|
||||
huggingFaceModelId,
|
||||
huggingFaceModelInfo,
|
||||
// Plan mode configurations
|
||||
planModeApiProvider: planModeApiProvider || apiProvider,
|
||||
planModeApiModelId,
|
||||
planModeThinkingBudgetTokens,
|
||||
planModeReasoningEffort,
|
||||
planModeVsCodeLmModelSelector,
|
||||
planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId,
|
||||
planModeOpenRouterModelId,
|
||||
planModeOpenRouterModelInfo,
|
||||
planModeOpenAiModelId,
|
||||
planModeOpenAiModelInfo,
|
||||
planModeOllamaModelId,
|
||||
planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo,
|
||||
planModeRequestyModelId,
|
||||
planModeRequestyModelInfo,
|
||||
planModeTogetherModelId,
|
||||
planModeFireworksModelId,
|
||||
planModeSapAiCoreModelId,
|
||||
planModeGroqModelId,
|
||||
planModeGroqModelInfo,
|
||||
planModeHuggingFaceModelId,
|
||||
planModeHuggingFaceModelInfo,
|
||||
// Act mode configurations
|
||||
actModeApiProvider: actModeApiProvider || apiProvider,
|
||||
actModeApiModelId,
|
||||
actModeThinkingBudgetTokens,
|
||||
actModeReasoningEffort,
|
||||
actModeVsCodeLmModelSelector,
|
||||
actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId,
|
||||
actModeOpenRouterModelId,
|
||||
actModeOpenRouterModelInfo,
|
||||
actModeOpenAiModelId,
|
||||
actModeOpenAiModelInfo,
|
||||
actModeOllamaModelId,
|
||||
actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo,
|
||||
actModeRequestyModelId,
|
||||
actModeRequestyModelInfo,
|
||||
actModeTogetherModelId,
|
||||
actModeFireworksModelId,
|
||||
actModeSapAiCoreModelId,
|
||||
actModeGroqModelId,
|
||||
actModeGroqModelInfo,
|
||||
},
|
||||
isNewUser: isNewUser ?? true,
|
||||
welcomeViewCompleted,
|
||||
@@ -486,15 +543,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
mode: currentMode || "act", // Merge mode from global state
|
||||
},
|
||||
userInfo,
|
||||
previousModeApiProvider,
|
||||
previousModeModelId,
|
||||
previousModeModelInfo,
|
||||
previousModeVsCodeLmModelSelector,
|
||||
previousModeThinkingBudgetTokens,
|
||||
previousModeReasoningEffort,
|
||||
previousModeAwsBedrockCustomSelected,
|
||||
previousModeAwsBedrockCustomModelBaseId,
|
||||
previousModeSapAiCoreModelId,
|
||||
mcpMarketplaceEnabled: mcpMarketplaceEnabled,
|
||||
mcpDisplayMode: mcpDisplayMode ?? DEFAULT_MCP_DISPLAY_MODE,
|
||||
mcpResponsesCollapsed: mcpResponsesCollapsed,
|
||||
@@ -511,8 +559,6 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
|
||||
|
||||
export async function updateApiConfiguration(context: vscode.ExtensionContext, apiConfiguration: ApiConfiguration) {
|
||||
const {
|
||||
apiProvider,
|
||||
apiModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
awsAccessKey,
|
||||
@@ -526,19 +572,13 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
|
||||
awsProfile,
|
||||
awsUseProfile,
|
||||
awsAuthentication,
|
||||
awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId,
|
||||
vertexProjectId,
|
||||
vertexRegion,
|
||||
openAiBaseUrl,
|
||||
openAiApiKey,
|
||||
openAiModelId,
|
||||
openAiModelInfo,
|
||||
openAiHeaders,
|
||||
ollamaModelId,
|
||||
ollamaBaseUrl,
|
||||
ollamaApiOptionsCtxNum,
|
||||
lmStudioModelId,
|
||||
lmStudioBaseUrl,
|
||||
anthropicBaseUrl,
|
||||
geminiApiKey,
|
||||
@@ -546,21 +586,13 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
|
||||
openAiNativeApiKey,
|
||||
deepSeekApiKey,
|
||||
requestyApiKey,
|
||||
requestyModelId,
|
||||
requestyModelInfo,
|
||||
togetherApiKey,
|
||||
togetherModelId,
|
||||
qwenApiKey,
|
||||
doubaoApiKey,
|
||||
mistralApiKey,
|
||||
azureApiVersion,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openRouterProviderSorting,
|
||||
vsCodeLmModelSelector,
|
||||
liteLlmBaseUrl,
|
||||
liteLlmModelId,
|
||||
liteLlmModelInfo,
|
||||
liteLlmApiKey,
|
||||
liteLlmUsePromptCache,
|
||||
qwenApiLine,
|
||||
@@ -568,19 +600,14 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
|
||||
asksageApiKey,
|
||||
asksageApiUrl,
|
||||
xaiApiKey,
|
||||
thinkingBudgetTokens,
|
||||
reasoningEffort,
|
||||
clineAccountId,
|
||||
sambanovaApiKey,
|
||||
cerebrasApiKey,
|
||||
groqApiKey,
|
||||
groqModelId,
|
||||
groqModelInfo,
|
||||
moonshotApiKey,
|
||||
nebiusApiKey,
|
||||
favoritedModelIds,
|
||||
fireworksApiKey,
|
||||
fireworksModelId,
|
||||
fireworksModelMaxCompletionTokens,
|
||||
fireworksModelMaxTokens,
|
||||
sapAiCoreClientId,
|
||||
@@ -588,40 +615,113 @@ export async function updateApiConfiguration(context: vscode.ExtensionContext, a
|
||||
sapAiCoreBaseUrl,
|
||||
sapAiCoreTokenUrl,
|
||||
sapAiResourceGroup,
|
||||
sapAiCoreModelId,
|
||||
claudeCodePath,
|
||||
huggingFaceApiKey,
|
||||
huggingFaceModelId,
|
||||
huggingFaceModelInfo,
|
||||
// Plan mode configurations
|
||||
planModeApiProvider,
|
||||
planModeApiModelId,
|
||||
planModeThinkingBudgetTokens,
|
||||
planModeReasoningEffort,
|
||||
planModeVsCodeLmModelSelector,
|
||||
planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId,
|
||||
planModeOpenRouterModelId,
|
||||
planModeOpenRouterModelInfo,
|
||||
planModeOpenAiModelId,
|
||||
planModeOpenAiModelInfo,
|
||||
planModeOllamaModelId,
|
||||
planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo,
|
||||
planModeRequestyModelId,
|
||||
planModeRequestyModelInfo,
|
||||
planModeTogetherModelId,
|
||||
planModeFireworksModelId,
|
||||
planModeSapAiCoreModelId,
|
||||
planModeGroqModelId,
|
||||
planModeGroqModelInfo,
|
||||
planModeHuggingFaceModelId,
|
||||
planModeHuggingFaceModelInfo,
|
||||
// Act mode configurations
|
||||
actModeApiProvider,
|
||||
actModeApiModelId,
|
||||
actModeThinkingBudgetTokens,
|
||||
actModeReasoningEffort,
|
||||
actModeVsCodeLmModelSelector,
|
||||
actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId,
|
||||
actModeOpenRouterModelId,
|
||||
actModeOpenRouterModelInfo,
|
||||
actModeOpenAiModelId,
|
||||
actModeOpenAiModelInfo,
|
||||
actModeOllamaModelId,
|
||||
actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo,
|
||||
actModeRequestyModelId,
|
||||
actModeRequestyModelInfo,
|
||||
actModeTogetherModelId,
|
||||
actModeFireworksModelId,
|
||||
actModeSapAiCoreModelId,
|
||||
actModeGroqModelId,
|
||||
actModeGroqModelInfo,
|
||||
actModeHuggingFaceModelId,
|
||||
actModeHuggingFaceModelInfo,
|
||||
} = apiConfiguration
|
||||
|
||||
// OPTIMIZED: Batch all global state updates into 2 operations instead of 47
|
||||
const batchedGlobalUpdates = {
|
||||
// Ephemeral model config updates (20 keys)
|
||||
apiProvider,
|
||||
apiModelId,
|
||||
thinkingBudgetTokens,
|
||||
reasoningEffort,
|
||||
vsCodeLmModelSelector,
|
||||
awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId,
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
openAiModelId,
|
||||
openAiModelInfo,
|
||||
ollamaModelId,
|
||||
lmStudioModelId,
|
||||
liteLlmModelId,
|
||||
liteLlmModelInfo,
|
||||
requestyModelId,
|
||||
requestyModelInfo,
|
||||
togetherModelId,
|
||||
fireworksModelId,
|
||||
groqModelId,
|
||||
groqModelInfo,
|
||||
sapAiCoreModelId,
|
||||
huggingFaceModelId,
|
||||
huggingFaceModelInfo,
|
||||
// Plan mode configuration updates
|
||||
planModeApiProvider,
|
||||
planModeApiModelId,
|
||||
planModeThinkingBudgetTokens,
|
||||
planModeReasoningEffort,
|
||||
planModeVsCodeLmModelSelector,
|
||||
planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId,
|
||||
planModeOpenRouterModelId,
|
||||
planModeOpenRouterModelInfo,
|
||||
planModeOpenAiModelId,
|
||||
planModeOpenAiModelInfo,
|
||||
planModeOllamaModelId,
|
||||
planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo,
|
||||
planModeRequestyModelId,
|
||||
planModeRequestyModelInfo,
|
||||
planModeTogetherModelId,
|
||||
planModeFireworksModelId,
|
||||
planModeSapAiCoreModelId,
|
||||
planModeGroqModelId,
|
||||
planModeGroqModelInfo,
|
||||
planModeHuggingFaceModelId,
|
||||
planModeHuggingFaceModelInfo,
|
||||
|
||||
// Act mode configuration updates
|
||||
actModeApiProvider,
|
||||
actModeApiModelId,
|
||||
actModeThinkingBudgetTokens,
|
||||
actModeReasoningEffort,
|
||||
actModeVsCodeLmModelSelector,
|
||||
actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId,
|
||||
actModeOpenRouterModelId,
|
||||
actModeOpenRouterModelInfo,
|
||||
actModeOpenAiModelId,
|
||||
actModeOpenAiModelInfo,
|
||||
actModeOllamaModelId,
|
||||
actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo,
|
||||
actModeRequestyModelId,
|
||||
actModeRequestyModelInfo,
|
||||
actModeTogetherModelId,
|
||||
actModeFireworksModelId,
|
||||
actModeSapAiCoreModelId,
|
||||
actModeGroqModelId,
|
||||
actModeGroqModelInfo,
|
||||
actModeHuggingFaceModelId,
|
||||
actModeHuggingFaceModelInfo,
|
||||
|
||||
// Global state updates (27 keys)
|
||||
awsRegion,
|
||||
|
||||
@@ -54,6 +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"
|
||||
|
||||
export class ToolExecutor {
|
||||
private autoApprover: AutoApprove
|
||||
@@ -90,6 +91,7 @@ export class ToolExecutor {
|
||||
private browserSettings: BrowserSettings,
|
||||
private cwd: string,
|
||||
private taskId: string,
|
||||
private chatSettings: ChatSettings,
|
||||
|
||||
// Callbacks to the Task (Entity)
|
||||
private say: (
|
||||
@@ -1917,7 +1919,12 @@ 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 providerAndModel = `${await getGlobalState(this.context, "apiProvider")} / ${this.api.getModel().id}`
|
||||
const currentMode = this.chatSettings.mode
|
||||
const apiProvider =
|
||||
currentMode === "plan"
|
||||
? await getGlobalState(this.context, "planModeApiProvider")
|
||||
: await getGlobalState(this.context, "actModeApiProvider")
|
||||
const providerAndModel = `${apiProvider} / ${this.api.getModel().id}`
|
||||
|
||||
// Ask user for confirmation
|
||||
const bugReportData = JSON.stringify({
|
||||
|
||||
+17
-6
@@ -261,12 +261,19 @@ export class Task {
|
||||
},
|
||||
}
|
||||
|
||||
if (apiConfiguration.apiProvider === "openai" || apiConfiguration.apiProvider === "openai-native") {
|
||||
effectiveApiConfiguration.reasoningEffort = chatSettings.openAIReasoningEffort
|
||||
const currentProvider =
|
||||
chatSettings.mode === "plan" ? apiConfiguration.planModeApiProvider : apiConfiguration.actModeApiProvider
|
||||
|
||||
if (currentProvider === "openai" || currentProvider === "openai-native") {
|
||||
if (chatSettings.mode === "plan") {
|
||||
effectiveApiConfiguration.planModeReasoningEffort = chatSettings.openAIReasoningEffort
|
||||
} else {
|
||||
effectiveApiConfiguration.actModeReasoningEffort = chatSettings.openAIReasoningEffort
|
||||
}
|
||||
}
|
||||
|
||||
// Now that taskId is initialized, we can build the API handler
|
||||
this.api = buildApiHandler(effectiveApiConfiguration)
|
||||
this.api = buildApiHandler(effectiveApiConfiguration, chatSettings.mode)
|
||||
|
||||
// Set taskId on browserSession for telemetry tracking
|
||||
this.browserSession.setTaskId(this.taskId)
|
||||
@@ -281,10 +288,10 @@ export class Task {
|
||||
// initialize telemetry
|
||||
if (historyItem) {
|
||||
// Open task from history
|
||||
telemetryService.captureTaskRestarted(this.taskId, apiConfiguration.apiProvider)
|
||||
telemetryService.captureTaskRestarted(this.taskId, currentProvider)
|
||||
} else {
|
||||
// New task started
|
||||
telemetryService.captureTaskCreated(this.taskId, apiConfiguration.apiProvider)
|
||||
telemetryService.captureTaskCreated(this.taskId, currentProvider)
|
||||
}
|
||||
|
||||
this.toolExecutor = new ToolExecutor(
|
||||
@@ -304,6 +311,7 @@ export class Task {
|
||||
this.browserSettings,
|
||||
cwd,
|
||||
this.taskId,
|
||||
this.chatSettings,
|
||||
this.say.bind(this),
|
||||
this.ask.bind(this),
|
||||
this.saveCheckpoint.bind(this),
|
||||
@@ -1591,7 +1599,10 @@ export class Task {
|
||||
|
||||
private async getCurrentProviderInfo(): Promise<{ modelId: string; providerId: string }> {
|
||||
const modelId = this.api.getModel()?.id
|
||||
const providerId = (await getGlobalState(this.getContext(), "apiProvider")) as string
|
||||
const providerId =
|
||||
this.chatSettings.mode === "plan"
|
||||
? ((await getGlobalState(this.getContext(), "planModeApiProvider")) as string)
|
||||
: ((await getGlobalState(this.getContext(), "actModeApiProvider")) as string)
|
||||
return { modelId, providerId }
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
migrateCustomInstructionsToGlobalRules,
|
||||
migrateModeFromWorkspaceStorageToControllerState,
|
||||
migrateWelcomeViewCompleted,
|
||||
migrateLegacyApiConfigurationToModeSpecific,
|
||||
} from "./core/storage/state-migrations"
|
||||
|
||||
import { sendFocusChatInputEvent } from "./core/controller/ui/subscribeToFocusChatInput"
|
||||
@@ -75,6 +76,9 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// 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,6 +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"
|
||||
|
||||
/**
|
||||
* TelemetryService handles telemetry event tracking for the Cline extension
|
||||
@@ -312,7 +313,7 @@ class TelemetryService {
|
||||
* @param taskId Unique identifier for the task
|
||||
* @param mode The mode being switched to (plan or act)
|
||||
*/
|
||||
public captureModeSwitch(taskId: string, mode: "plan" | "act") {
|
||||
public captureModeSwitch(taskId: string, mode: Mode) {
|
||||
this.capture({
|
||||
event: TelemetryService.EVENTS.TASK.MODE_SWITCH,
|
||||
properties: {
|
||||
@@ -534,7 +535,7 @@ class TelemetryService {
|
||||
* @param qty The quantity of options that were presented
|
||||
* @param mode The mode in which the option was selected ("plan" or "act")
|
||||
*/
|
||||
public captureOptionSelected(taskId: string, qty: number, mode: "plan" | "act") {
|
||||
public captureOptionSelected(taskId: string, qty: number, mode: Mode) {
|
||||
this.capture({
|
||||
event: TelemetryService.EVENTS.TASK.OPTION_SELECTED,
|
||||
properties: {
|
||||
@@ -551,7 +552,7 @@ class TelemetryService {
|
||||
* @param qty The quantity of options that were presented
|
||||
* @param mode The mode in which the custom response was provided ("plan" or "act")
|
||||
*/
|
||||
public captureOptionsIgnored(taskId: string, qty: number, mode: "plan" | "act") {
|
||||
public captureOptionsIgnored(taskId: string, qty: number, mode: Mode) {
|
||||
this.capture({
|
||||
event: TelemetryService.EVENTS.TASK.OPTIONS_IGNORED,
|
||||
properties: {
|
||||
|
||||
@@ -274,7 +274,8 @@ export function createTestServer(webviewProvider?: WebviewProvider): http.Server
|
||||
await updateApiConfiguration(visibleWebview.controller.context, updatedConfig)
|
||||
|
||||
// Update global state to use cline provider
|
||||
await updateGlobalState(visibleWebview.controller.context, "apiProvider", "cline" as ApiProvider)
|
||||
await updateGlobalState(visibleWebview.controller.context, "planModeApiProvider", "cline")
|
||||
await updateGlobalState(visibleWebview.controller.context, "actModeApiProvider", "cline")
|
||||
|
||||
// Post state to webview to reflect changes
|
||||
await visibleWebview.controller.postStateToWebview()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
export type OpenAIReasoningEffort = "low" | "medium" | "high"
|
||||
|
||||
export type Mode = "plan" | "act"
|
||||
|
||||
export interface ChatSettings {
|
||||
mode: "plan" | "act"
|
||||
mode: Mode
|
||||
preferredLanguage?: string
|
||||
openAIReasoningEffort?: OpenAIReasoningEffort
|
||||
}
|
||||
|
||||
+52
-24
@@ -32,20 +32,16 @@ export type ApiProvider =
|
||||
| "huggingface"
|
||||
|
||||
export interface ApiHandlerOptions {
|
||||
apiModelId?: string
|
||||
// Global configuration (not mode-specific)
|
||||
apiKey?: string // anthropic
|
||||
clineAccountId?: string
|
||||
taskId?: string // Used to identify the task in API requests
|
||||
liteLlmBaseUrl?: string
|
||||
liteLlmModelId?: string
|
||||
liteLlmApiKey?: string
|
||||
liteLlmUsePromptCache?: boolean
|
||||
openAiHeaders?: Record<string, string> // Custom headers for OpenAI requests
|
||||
liteLlmModelInfo?: LiteLLMModelInfo
|
||||
anthropicBaseUrl?: string
|
||||
openRouterApiKey?: string
|
||||
openRouterModelId?: string
|
||||
openRouterModelInfo?: ModelInfo
|
||||
openRouterProviderSorting?: string
|
||||
awsAccessKey?: string
|
||||
awsSecretKey?: string
|
||||
@@ -58,67 +54,99 @@ export interface ApiHandlerOptions {
|
||||
awsProfile?: string
|
||||
awsBedrockApiKey?: string
|
||||
awsBedrockEndpoint?: string
|
||||
awsBedrockCustomSelected?: boolean
|
||||
awsBedrockCustomModelBaseId?: BedrockModelId
|
||||
claudeCodePath?: string
|
||||
vertexProjectId?: string
|
||||
vertexRegion?: string
|
||||
openAiBaseUrl?: string
|
||||
openAiApiKey?: string
|
||||
openAiModelId?: string
|
||||
openAiModelInfo?: OpenAiCompatibleModelInfo
|
||||
ollamaModelId?: string
|
||||
ollamaBaseUrl?: string
|
||||
ollamaApiOptionsCtxNum?: string
|
||||
lmStudioModelId?: string
|
||||
lmStudioBaseUrl?: string
|
||||
geminiApiKey?: string
|
||||
geminiBaseUrl?: string
|
||||
openAiNativeApiKey?: string
|
||||
deepSeekApiKey?: string
|
||||
requestyApiKey?: string
|
||||
requestyModelId?: string
|
||||
requestyModelInfo?: ModelInfo
|
||||
togetherApiKey?: string
|
||||
togetherModelId?: string
|
||||
fireworksApiKey?: string
|
||||
fireworksModelId?: string
|
||||
fireworksModelMaxCompletionTokens?: number
|
||||
fireworksModelMaxTokens?: number
|
||||
qwenApiKey?: string
|
||||
doubaoApiKey?: string
|
||||
mistralApiKey?: string
|
||||
azureApiVersion?: string
|
||||
vsCodeLmModelSelector?: LanguageModelChatSelector
|
||||
qwenApiLine?: string
|
||||
moonshotApiLine?: string
|
||||
moonshotApiKey?: string
|
||||
huggingFaceApiKey?: string
|
||||
huggingFaceModelId?: string
|
||||
huggingFaceModelInfo?: ModelInfo
|
||||
nebiusApiKey?: string
|
||||
asksageApiUrl?: string
|
||||
asksageApiKey?: string
|
||||
xaiApiKey?: string
|
||||
thinkingBudgetTokens?: number
|
||||
reasoningEffort?: string
|
||||
sambanovaApiKey?: string
|
||||
cerebrasApiKey?: string
|
||||
groqApiKey?: string
|
||||
groqModelId?: string
|
||||
groqModelInfo?: ModelInfo
|
||||
requestTimeoutMs?: number
|
||||
sapAiCoreClientId?: string
|
||||
sapAiCoreClientSecret?: string
|
||||
sapAiResourceGroup?: string
|
||||
sapAiCoreTokenUrl?: string
|
||||
sapAiCoreBaseUrl?: string
|
||||
sapAiCoreModelId?: string
|
||||
onRetryAttempt?: (attempt: number, maxRetries: number, delay: number, error: any) => void
|
||||
// Plan mode configurations
|
||||
planModeApiModelId?: string
|
||||
planModeThinkingBudgetTokens?: number
|
||||
planModeReasoningEffort?: string
|
||||
planModeVsCodeLmModelSelector?: LanguageModelChatSelector
|
||||
planModeAwsBedrockCustomSelected?: boolean
|
||||
planModeAwsBedrockCustomModelBaseId?: BedrockModelId
|
||||
planModeOpenRouterModelId?: string
|
||||
planModeOpenRouterModelInfo?: ModelInfo
|
||||
planModeOpenAiModelId?: string
|
||||
planModeOpenAiModelInfo?: OpenAiCompatibleModelInfo
|
||||
planModeOllamaModelId?: string
|
||||
planModeLmStudioModelId?: string
|
||||
planModeLiteLlmModelId?: string
|
||||
planModeLiteLlmModelInfo?: LiteLLMModelInfo
|
||||
planModeRequestyModelId?: string
|
||||
planModeRequestyModelInfo?: ModelInfo
|
||||
planModeTogetherModelId?: string
|
||||
planModeFireworksModelId?: string
|
||||
planModeSapAiCoreModelId?: string
|
||||
planModeGroqModelId?: string
|
||||
planModeGroqModelInfo?: ModelInfo
|
||||
planModeHuggingFaceModelId?: string
|
||||
planModeHuggingFaceModelInfo?: ModelInfo
|
||||
// Act mode configurations
|
||||
|
||||
actModeApiModelId?: string
|
||||
actModeThinkingBudgetTokens?: number
|
||||
actModeReasoningEffort?: string
|
||||
actModeVsCodeLmModelSelector?: LanguageModelChatSelector
|
||||
actModeAwsBedrockCustomSelected?: boolean
|
||||
actModeAwsBedrockCustomModelBaseId?: BedrockModelId
|
||||
actModeOpenRouterModelId?: string
|
||||
actModeOpenRouterModelInfo?: ModelInfo
|
||||
actModeOpenAiModelId?: string
|
||||
actModeOpenAiModelInfo?: OpenAiCompatibleModelInfo
|
||||
actModeOllamaModelId?: string
|
||||
actModeLmStudioModelId?: string
|
||||
actModeLiteLlmModelId?: string
|
||||
actModeLiteLlmModelInfo?: LiteLLMModelInfo
|
||||
actModeRequestyModelId?: string
|
||||
actModeRequestyModelInfo?: ModelInfo
|
||||
actModeTogetherModelId?: string
|
||||
actModeFireworksModelId?: string
|
||||
actModeSapAiCoreModelId?: string
|
||||
actModeGroqModelId?: string
|
||||
actModeGroqModelInfo?: ModelInfo
|
||||
actModeHuggingFaceModelId?: string
|
||||
actModeHuggingFaceModelInfo?: ModelInfo
|
||||
}
|
||||
|
||||
export type ApiConfiguration = ApiHandlerOptions & {
|
||||
apiProvider?: ApiProvider
|
||||
planModeApiProvider?: ApiProvider
|
||||
actModeApiProvider?: ApiProvider
|
||||
favoritedModelIds?: string[]
|
||||
}
|
||||
|
||||
|
||||
@@ -318,20 +318,16 @@ function convertProtoToApiProvider(provider: ProtoApiProvider): ApiProvider {
|
||||
// Converts application ApiConfiguration to proto ApiConfiguration
|
||||
export function convertApiConfigurationToProto(config: ApiConfiguration): ProtoApiConfiguration {
|
||||
return {
|
||||
apiModelId: config.apiModelId,
|
||||
// Global configuration fields
|
||||
apiKey: config.apiKey,
|
||||
clineAccountId: config.clineAccountId,
|
||||
taskId: config.taskId,
|
||||
liteLlmBaseUrl: config.liteLlmBaseUrl,
|
||||
liteLlmModelId: config.liteLlmModelId,
|
||||
liteLlmApiKey: config.liteLlmApiKey,
|
||||
liteLlmUsePromptCache: config.liteLlmUsePromptCache,
|
||||
openAiHeaders: config.openAiHeaders || {},
|
||||
liteLlmModelInfo: convertLiteLLMModelInfoToProto(config.liteLlmModelInfo),
|
||||
anthropicBaseUrl: config.anthropicBaseUrl,
|
||||
openRouterApiKey: config.openRouterApiKey,
|
||||
openRouterModelId: config.openRouterModelId,
|
||||
openRouterModelInfo: convertModelInfoToProtoOpenRouter(config.openRouterModelInfo),
|
||||
openRouterProviderSorting: config.openRouterProviderSorting,
|
||||
awsAccessKey: config.awsAccessKey,
|
||||
awsSecretKey: config.awsSecretKey,
|
||||
@@ -344,83 +340,115 @@ export function convertApiConfigurationToProto(config: ApiConfiguration): ProtoA
|
||||
awsProfile: config.awsProfile,
|
||||
awsBedrockApiKey: config.awsBedrockApiKey,
|
||||
awsBedrockEndpoint: config.awsBedrockEndpoint,
|
||||
awsBedrockCustomSelected: config.awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId: config.awsBedrockCustomModelBaseId as string | undefined,
|
||||
claudeCodePath: config.claudeCodePath,
|
||||
vertexProjectId: config.vertexProjectId,
|
||||
vertexRegion: config.vertexRegion,
|
||||
openAiBaseUrl: config.openAiBaseUrl,
|
||||
openAiApiKey: config.openAiApiKey,
|
||||
openAiModelId: config.openAiModelId,
|
||||
openAiModelInfo: convertOpenAiCompatibleModelInfoToProto(config.openAiModelInfo),
|
||||
ollamaModelId: config.ollamaModelId,
|
||||
ollamaBaseUrl: config.ollamaBaseUrl,
|
||||
ollamaApiOptionsCtxNum: config.ollamaApiOptionsCtxNum,
|
||||
lmStudioModelId: config.lmStudioModelId,
|
||||
lmStudioBaseUrl: config.lmStudioBaseUrl,
|
||||
geminiApiKey: config.geminiApiKey,
|
||||
geminiBaseUrl: config.geminiBaseUrl,
|
||||
openAiNativeApiKey: config.openAiNativeApiKey,
|
||||
deepSeekApiKey: config.deepSeekApiKey,
|
||||
requestyApiKey: config.requestyApiKey,
|
||||
requestyModelId: config.requestyModelId,
|
||||
requestyModelInfo: convertModelInfoToProtoOpenRouter(config.requestyModelInfo),
|
||||
togetherApiKey: config.togetherApiKey,
|
||||
togetherModelId: config.togetherModelId,
|
||||
fireworksApiKey: config.fireworksApiKey,
|
||||
fireworksModelId: config.fireworksModelId,
|
||||
fireworksModelMaxCompletionTokens: config.fireworksModelMaxCompletionTokens,
|
||||
fireworksModelMaxTokens: config.fireworksModelMaxTokens,
|
||||
qwenApiKey: config.qwenApiKey,
|
||||
doubaoApiKey: config.doubaoApiKey,
|
||||
mistralApiKey: config.mistralApiKey,
|
||||
azureApiVersion: config.azureApiVersion,
|
||||
vsCodeLmModelSelector: config.vsCodeLmModelSelector,
|
||||
qwenApiLine: config.qwenApiLine,
|
||||
moonshotApiLine: config.moonshotApiLine,
|
||||
moonshotApiKey: config.moonshotApiKey,
|
||||
huggingFaceApiKey: config.huggingFaceApiKey,
|
||||
huggingFaceModelId: config.huggingFaceModelId,
|
||||
huggingFaceModelInfo: convertModelInfoToProtoOpenRouter(config.huggingFaceModelInfo),
|
||||
nebiusApiKey: config.nebiusApiKey,
|
||||
asksageApiUrl: config.asksageApiUrl,
|
||||
asksageApiKey: config.asksageApiKey,
|
||||
xaiApiKey: config.xaiApiKey,
|
||||
thinkingBudgetTokens: config.thinkingBudgetTokens,
|
||||
reasoningEffort: config.reasoningEffort,
|
||||
sambanovaApiKey: config.sambanovaApiKey,
|
||||
cerebrasApiKey: config.cerebrasApiKey,
|
||||
groqApiKey: config.groqApiKey,
|
||||
groqModelId: config.groqModelId,
|
||||
groqModelInfo: convertModelInfoToProtoOpenRouter(config.groqModelInfo),
|
||||
requestTimeoutMs: config.requestTimeoutMs,
|
||||
apiProvider: config.apiProvider ? convertApiProviderToProto(config.apiProvider) : undefined,
|
||||
favoritedModelIds: config.favoritedModelIds || [],
|
||||
sapAiCoreClientId: config.sapAiCoreClientId,
|
||||
sapAiCoreClientSecret: config.sapAiCoreClientSecret,
|
||||
sapAiResourceGroup: config.sapAiResourceGroup,
|
||||
sapAiCoreTokenUrl: config.sapAiCoreTokenUrl,
|
||||
sapAiCoreBaseUrl: config.sapAiCoreBaseUrl,
|
||||
claudeCodePath: config.claudeCodePath,
|
||||
|
||||
// Plan mode configurations
|
||||
planModeApiProvider: config.planModeApiProvider ? convertApiProviderToProto(config.planModeApiProvider) : undefined,
|
||||
planModeApiModelId: config.planModeApiModelId,
|
||||
planModeThinkingBudgetTokens: config.planModeThinkingBudgetTokens,
|
||||
planModeReasoningEffort: config.planModeReasoningEffort,
|
||||
planModeVsCodeLmModelSelector: config.planModeVsCodeLmModelSelector,
|
||||
planModeAwsBedrockCustomSelected: config.planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId: config.planModeAwsBedrockCustomModelBaseId as string | undefined,
|
||||
planModeOpenRouterModelId: config.planModeOpenRouterModelId,
|
||||
planModeOpenRouterModelInfo: convertModelInfoToProtoOpenRouter(config.planModeOpenRouterModelInfo),
|
||||
planModeOpenAiModelId: config.planModeOpenAiModelId,
|
||||
planModeOpenAiModelInfo: convertOpenAiCompatibleModelInfoToProto(config.planModeOpenAiModelInfo),
|
||||
planModeOllamaModelId: config.planModeOllamaModelId,
|
||||
planModeLmStudioModelId: config.planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId: config.planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo: convertLiteLLMModelInfoToProto(config.planModeLiteLlmModelInfo),
|
||||
planModeRequestyModelId: config.planModeRequestyModelId,
|
||||
planModeRequestyModelInfo: convertModelInfoToProtoOpenRouter(config.planModeRequestyModelInfo),
|
||||
planModeTogetherModelId: config.planModeTogetherModelId,
|
||||
planModeFireworksModelId: config.planModeFireworksModelId,
|
||||
planModeGroqModelId: config.planModeGroqModelId,
|
||||
planModeGroqModelInfo: convertModelInfoToProtoOpenRouter(config.planModeGroqModelInfo),
|
||||
planModeHuggingFaceModelId: config.planModeHuggingFaceModelId,
|
||||
planModeHuggingFaceModelInfo: convertModelInfoToProtoOpenRouter(config.planModeHuggingFaceModelInfo),
|
||||
planModeSapAiCoreModelId: config.planModeSapAiCoreModelId,
|
||||
|
||||
// Act mode configurations
|
||||
actModeApiProvider: config.actModeApiProvider ? convertApiProviderToProto(config.actModeApiProvider) : undefined,
|
||||
actModeApiModelId: config.actModeApiModelId,
|
||||
actModeThinkingBudgetTokens: config.actModeThinkingBudgetTokens,
|
||||
actModeReasoningEffort: config.actModeReasoningEffort,
|
||||
actModeVsCodeLmModelSelector: config.actModeVsCodeLmModelSelector,
|
||||
actModeAwsBedrockCustomSelected: config.actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId: config.actModeAwsBedrockCustomModelBaseId as string | undefined,
|
||||
actModeOpenRouterModelId: config.actModeOpenRouterModelId,
|
||||
actModeOpenRouterModelInfo: convertModelInfoToProtoOpenRouter(config.actModeOpenRouterModelInfo),
|
||||
actModeOpenAiModelId: config.actModeOpenAiModelId,
|
||||
actModeOpenAiModelInfo: convertOpenAiCompatibleModelInfoToProto(config.actModeOpenAiModelInfo),
|
||||
actModeOllamaModelId: config.actModeOllamaModelId,
|
||||
actModeLmStudioModelId: config.actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId: config.actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo: convertLiteLLMModelInfoToProto(config.actModeLiteLlmModelInfo),
|
||||
actModeRequestyModelId: config.actModeRequestyModelId,
|
||||
actModeRequestyModelInfo: convertModelInfoToProtoOpenRouter(config.actModeRequestyModelInfo),
|
||||
actModeTogetherModelId: config.actModeTogetherModelId,
|
||||
actModeFireworksModelId: config.actModeFireworksModelId,
|
||||
actModeGroqModelId: config.actModeGroqModelId,
|
||||
actModeGroqModelInfo: convertModelInfoToProtoOpenRouter(config.actModeGroqModelInfo),
|
||||
actModeHuggingFaceModelId: config.actModeHuggingFaceModelId,
|
||||
actModeHuggingFaceModelInfo: convertModelInfoToProtoOpenRouter(config.actModeHuggingFaceModelInfo),
|
||||
actModeSapAiCoreModelId: config.actModeSapAiCoreModelId,
|
||||
|
||||
// Favorited model IDs
|
||||
favoritedModelIds: config.favoritedModelIds || [],
|
||||
}
|
||||
}
|
||||
|
||||
// Converts proto ApiConfiguration to application ApiConfiguration
|
||||
export function convertProtoToApiConfiguration(protoConfig: ProtoApiConfiguration): ApiConfiguration {
|
||||
return {
|
||||
apiModelId: protoConfig.apiModelId,
|
||||
// Global configuration fields
|
||||
apiKey: protoConfig.apiKey,
|
||||
clineAccountId: protoConfig.clineAccountId,
|
||||
taskId: protoConfig.taskId,
|
||||
liteLlmBaseUrl: protoConfig.liteLlmBaseUrl,
|
||||
liteLlmModelId: protoConfig.liteLlmModelId,
|
||||
liteLlmApiKey: protoConfig.liteLlmApiKey,
|
||||
liteLlmUsePromptCache: protoConfig.liteLlmUsePromptCache,
|
||||
openAiHeaders: Object.keys(protoConfig.openAiHeaders).length > 0 ? protoConfig.openAiHeaders : undefined,
|
||||
liteLlmModelInfo: convertProtoToLiteLLMModelInfo(protoConfig.liteLlmModelInfo),
|
||||
openAiHeaders: Object.keys(protoConfig.openAiHeaders || {}).length > 0 ? protoConfig.openAiHeaders : undefined,
|
||||
anthropicBaseUrl: protoConfig.anthropicBaseUrl,
|
||||
openRouterApiKey: protoConfig.openRouterApiKey,
|
||||
openRouterModelId: protoConfig.openRouterModelId,
|
||||
openRouterModelInfo: convertProtoToModelInfo(protoConfig.openRouterModelInfo),
|
||||
openRouterProviderSorting: protoConfig.openRouterProviderSorting,
|
||||
awsAccessKey: protoConfig.awsAccessKey,
|
||||
awsSecretKey: protoConfig.awsSecretKey,
|
||||
@@ -433,62 +461,103 @@ export function convertProtoToApiConfiguration(protoConfig: ProtoApiConfiguratio
|
||||
awsProfile: protoConfig.awsProfile,
|
||||
awsBedrockApiKey: protoConfig.awsBedrockApiKey,
|
||||
awsBedrockEndpoint: protoConfig.awsBedrockEndpoint,
|
||||
awsBedrockCustomSelected: protoConfig.awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId: protoConfig.awsBedrockCustomModelBaseId as BedrockModelId | undefined,
|
||||
claudeCodePath: protoConfig.claudeCodePath,
|
||||
vertexProjectId: protoConfig.vertexProjectId,
|
||||
vertexRegion: protoConfig.vertexRegion,
|
||||
openAiBaseUrl: protoConfig.openAiBaseUrl,
|
||||
openAiApiKey: protoConfig.openAiApiKey,
|
||||
openAiModelId: protoConfig.openAiModelId,
|
||||
openAiModelInfo: convertProtoToOpenAiCompatibleModelInfo(protoConfig.openAiModelInfo),
|
||||
ollamaModelId: protoConfig.ollamaModelId,
|
||||
ollamaBaseUrl: protoConfig.ollamaBaseUrl,
|
||||
ollamaApiOptionsCtxNum: protoConfig.ollamaApiOptionsCtxNum,
|
||||
lmStudioModelId: protoConfig.lmStudioModelId,
|
||||
lmStudioBaseUrl: protoConfig.lmStudioBaseUrl,
|
||||
geminiApiKey: protoConfig.geminiApiKey,
|
||||
geminiBaseUrl: protoConfig.geminiBaseUrl,
|
||||
openAiNativeApiKey: protoConfig.openAiNativeApiKey,
|
||||
deepSeekApiKey: protoConfig.deepSeekApiKey,
|
||||
requestyApiKey: protoConfig.requestyApiKey,
|
||||
requestyModelId: protoConfig.requestyModelId,
|
||||
requestyModelInfo: convertProtoToModelInfo(protoConfig.requestyModelInfo),
|
||||
togetherApiKey: protoConfig.togetherApiKey,
|
||||
togetherModelId: protoConfig.togetherModelId,
|
||||
fireworksApiKey: protoConfig.fireworksApiKey,
|
||||
fireworksModelId: protoConfig.fireworksModelId,
|
||||
fireworksModelMaxCompletionTokens: protoConfig.fireworksModelMaxCompletionTokens,
|
||||
fireworksModelMaxTokens: protoConfig.fireworksModelMaxTokens,
|
||||
qwenApiKey: protoConfig.qwenApiKey,
|
||||
doubaoApiKey: protoConfig.doubaoApiKey,
|
||||
mistralApiKey: protoConfig.mistralApiKey,
|
||||
azureApiVersion: protoConfig.azureApiVersion,
|
||||
vsCodeLmModelSelector: protoConfig.vsCodeLmModelSelector,
|
||||
qwenApiLine: protoConfig.qwenApiLine,
|
||||
moonshotApiLine: protoConfig.moonshotApiLine,
|
||||
moonshotApiKey: protoConfig.moonshotApiKey,
|
||||
huggingFaceApiKey: protoConfig.huggingFaceApiKey,
|
||||
huggingFaceModelId: protoConfig.huggingFaceModelId,
|
||||
huggingFaceModelInfo: convertProtoToModelInfo(protoConfig.huggingFaceModelInfo),
|
||||
nebiusApiKey: protoConfig.nebiusApiKey,
|
||||
asksageApiUrl: protoConfig.asksageApiUrl,
|
||||
asksageApiKey: protoConfig.asksageApiKey,
|
||||
xaiApiKey: protoConfig.xaiApiKey,
|
||||
thinkingBudgetTokens: protoConfig.thinkingBudgetTokens,
|
||||
reasoningEffort: protoConfig.reasoningEffort,
|
||||
sambanovaApiKey: protoConfig.sambanovaApiKey,
|
||||
cerebrasApiKey: protoConfig.cerebrasApiKey,
|
||||
groqApiKey: protoConfig.groqApiKey,
|
||||
groqModelId: protoConfig.groqModelId,
|
||||
groqModelInfo: convertProtoToModelInfo(protoConfig.groqModelInfo),
|
||||
requestTimeoutMs: protoConfig.requestTimeoutMs,
|
||||
apiProvider: protoConfig.apiProvider !== undefined ? convertProtoToApiProvider(protoConfig.apiProvider) : undefined,
|
||||
favoritedModelIds: protoConfig.favoritedModelIds.length > 0 ? protoConfig.favoritedModelIds : undefined,
|
||||
sapAiCoreClientId: protoConfig.sapAiCoreClientId,
|
||||
sapAiCoreClientSecret: protoConfig.sapAiCoreClientSecret,
|
||||
sapAiResourceGroup: protoConfig.sapAiResourceGroup,
|
||||
sapAiCoreTokenUrl: protoConfig.sapAiCoreTokenUrl,
|
||||
sapAiCoreBaseUrl: protoConfig.sapAiCoreBaseUrl,
|
||||
claudeCodePath: protoConfig.claudeCodePath,
|
||||
|
||||
// Plan mode configurations
|
||||
planModeApiProvider:
|
||||
protoConfig.planModeApiProvider !== undefined
|
||||
? convertProtoToApiProvider(protoConfig.planModeApiProvider)
|
||||
: undefined,
|
||||
planModeApiModelId: protoConfig.planModeApiModelId,
|
||||
planModeThinkingBudgetTokens: protoConfig.planModeThinkingBudgetTokens,
|
||||
planModeReasoningEffort: protoConfig.planModeReasoningEffort,
|
||||
planModeVsCodeLmModelSelector: protoConfig.planModeVsCodeLmModelSelector,
|
||||
planModeAwsBedrockCustomSelected: protoConfig.planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId: protoConfig.planModeAwsBedrockCustomModelBaseId as BedrockModelId | undefined,
|
||||
planModeOpenRouterModelId: protoConfig.planModeOpenRouterModelId,
|
||||
planModeOpenRouterModelInfo: convertProtoToModelInfo(protoConfig.planModeOpenRouterModelInfo),
|
||||
planModeOpenAiModelId: protoConfig.planModeOpenAiModelId,
|
||||
planModeOpenAiModelInfo: convertProtoToOpenAiCompatibleModelInfo(protoConfig.planModeOpenAiModelInfo),
|
||||
planModeOllamaModelId: protoConfig.planModeOllamaModelId,
|
||||
planModeLmStudioModelId: protoConfig.planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId: protoConfig.planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo: convertProtoToLiteLLMModelInfo(protoConfig.planModeLiteLlmModelInfo),
|
||||
planModeRequestyModelId: protoConfig.planModeRequestyModelId,
|
||||
planModeRequestyModelInfo: convertProtoToModelInfo(protoConfig.planModeRequestyModelInfo),
|
||||
planModeTogetherModelId: protoConfig.planModeTogetherModelId,
|
||||
planModeFireworksModelId: protoConfig.planModeFireworksModelId,
|
||||
planModeGroqModelId: protoConfig.planModeGroqModelId,
|
||||
planModeGroqModelInfo: convertProtoToModelInfo(protoConfig.planModeGroqModelInfo),
|
||||
planModeHuggingFaceModelId: protoConfig.planModeHuggingFaceModelId,
|
||||
planModeHuggingFaceModelInfo: convertProtoToModelInfo(protoConfig.planModeHuggingFaceModelInfo),
|
||||
planModeSapAiCoreModelId: protoConfig.planModeSapAiCoreModelId,
|
||||
|
||||
// Act mode configurations
|
||||
actModeApiProvider:
|
||||
protoConfig.actModeApiProvider !== undefined ? convertProtoToApiProvider(protoConfig.actModeApiProvider) : undefined,
|
||||
actModeApiModelId: protoConfig.actModeApiModelId,
|
||||
actModeThinkingBudgetTokens: protoConfig.actModeThinkingBudgetTokens,
|
||||
actModeReasoningEffort: protoConfig.actModeReasoningEffort,
|
||||
actModeVsCodeLmModelSelector: protoConfig.actModeVsCodeLmModelSelector,
|
||||
actModeAwsBedrockCustomSelected: protoConfig.actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId: protoConfig.actModeAwsBedrockCustomModelBaseId as BedrockModelId | undefined,
|
||||
actModeOpenRouterModelId: protoConfig.actModeOpenRouterModelId,
|
||||
actModeOpenRouterModelInfo: convertProtoToModelInfo(protoConfig.actModeOpenRouterModelInfo),
|
||||
actModeOpenAiModelId: protoConfig.actModeOpenAiModelId,
|
||||
actModeOpenAiModelInfo: convertProtoToOpenAiCompatibleModelInfo(protoConfig.actModeOpenAiModelInfo),
|
||||
actModeOllamaModelId: protoConfig.actModeOllamaModelId,
|
||||
actModeLmStudioModelId: protoConfig.actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId: protoConfig.actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo: convertProtoToLiteLLMModelInfo(protoConfig.actModeLiteLlmModelInfo),
|
||||
actModeRequestyModelId: protoConfig.actModeRequestyModelId,
|
||||
actModeRequestyModelInfo: convertProtoToModelInfo(protoConfig.actModeRequestyModelInfo),
|
||||
actModeTogetherModelId: protoConfig.actModeTogetherModelId,
|
||||
actModeFireworksModelId: protoConfig.actModeFireworksModelId,
|
||||
actModeGroqModelId: protoConfig.actModeGroqModelId,
|
||||
actModeGroqModelInfo: convertProtoToModelInfo(protoConfig.actModeGroqModelInfo),
|
||||
actModeHuggingFaceModelId: protoConfig.actModeHuggingFaceModelId,
|
||||
actModeHuggingFaceModelInfo: convertProtoToModelInfo(protoConfig.actModeHuggingFaceModelInfo),
|
||||
actModeSapAiCoreModelId: protoConfig.actModeSapAiCoreModelId,
|
||||
|
||||
// Favorited model IDs
|
||||
favoritedModelIds:
|
||||
protoConfig.favoritedModelIds && protoConfig.favoritedModelIds.length > 0 ? protoConfig.favoritedModelIds : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,49 +11,17 @@ import {
|
||||
*/
|
||||
export function convertApiConfigurationToProtoApiConfiguration(config: ApiConfiguration): ProtoApiConfiguration {
|
||||
return ProtoApiConfiguration.create({
|
||||
// Core API fields
|
||||
apiProvider: config.apiProvider,
|
||||
apiModelId: config.apiModelId,
|
||||
// Global configuration fields (not mode-specific)
|
||||
apiKey: config.apiKey,
|
||||
|
||||
// Provider-specific API keys
|
||||
clineAccountId: config.clineAccountId,
|
||||
openrouterApiKey: config.openRouterApiKey,
|
||||
taskId: config.taskId,
|
||||
liteLlmBaseUrl: config.liteLlmBaseUrl,
|
||||
liteLlmApiKey: config.liteLlmApiKey,
|
||||
liteLlmUsePromptCache: config.liteLlmUsePromptCache,
|
||||
openaiHeaders: config.openAiHeaders ? JSON.stringify(config.openAiHeaders) : undefined,
|
||||
anthropicBaseUrl: config.anthropicBaseUrl,
|
||||
openaiApiKey: config.openAiApiKey,
|
||||
openaiNativeApiKey: config.openAiNativeApiKey,
|
||||
geminiApiKey: config.geminiApiKey,
|
||||
deepseekApiKey: config.deepSeekApiKey,
|
||||
requestyApiKey: config.requestyApiKey,
|
||||
togetherApiKey: config.togetherApiKey,
|
||||
fireworksApiKey: config.fireworksApiKey,
|
||||
qwenApiKey: config.qwenApiKey,
|
||||
doubaoApiKey: config.doubaoApiKey,
|
||||
mistralApiKey: config.mistralApiKey,
|
||||
moonshotApiKey: config.moonshotApiKey,
|
||||
nebiusApiKey: config.nebiusApiKey,
|
||||
asksageApiKey: config.asksageApiKey,
|
||||
xaiApiKey: config.xaiApiKey,
|
||||
sambanovaApiKey: config.sambanovaApiKey,
|
||||
cerebrasApiKey: config.cerebrasApiKey,
|
||||
|
||||
// Model IDs - each provider has its own field
|
||||
openrouterModelId: config.openRouterModelId,
|
||||
openaiModelId: config.openAiModelId,
|
||||
anthropicModelId: config.apiModelId,
|
||||
bedrockModelId: config.apiModelId,
|
||||
vertexModelId: config.apiModelId,
|
||||
geminiModelId: config.apiModelId,
|
||||
ollamaModelId: config.ollamaModelId,
|
||||
lmStudioModelId: config.lmStudioModelId,
|
||||
litellmModelId: config.liteLlmModelId,
|
||||
requestyModelId: config.requestyModelId,
|
||||
togetherModelId: config.togetherModelId,
|
||||
fireworksModelId: config.fireworksModelId,
|
||||
|
||||
// AWS Bedrock fields
|
||||
awsBedrockCustomSelected: config.awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId: config.awsBedrockCustomModelBaseId,
|
||||
openrouterApiKey: config.openRouterApiKey,
|
||||
openrouterProviderSorting: config.openRouterProviderSorting,
|
||||
awsAccessKey: config.awsAccessKey,
|
||||
awsSecretKey: config.awsSecretKey,
|
||||
awsSessionToken: config.awsSessionToken,
|
||||
@@ -65,68 +33,101 @@ export function convertApiConfigurationToProtoApiConfiguration(config: ApiConfig
|
||||
awsProfile: config.awsProfile,
|
||||
awsBedrockApiKey: config.awsBedrockApiKey,
|
||||
awsBedrockEndpoint: config.awsBedrockEndpoint,
|
||||
|
||||
// Vertex AI fields
|
||||
claudeCodePath: config.claudeCodePath,
|
||||
vertexProjectId: config.vertexProjectId,
|
||||
vertexRegion: config.vertexRegion,
|
||||
|
||||
// Base URLs and endpoints
|
||||
openaiBaseUrl: config.openAiBaseUrl,
|
||||
openaiApiKey: config.openAiApiKey,
|
||||
ollamaBaseUrl: config.ollamaBaseUrl,
|
||||
ollamaApiOptionsCtxNum: config.ollamaApiOptionsCtxNum,
|
||||
lmStudioBaseUrl: config.lmStudioBaseUrl,
|
||||
geminiApiKey: config.geminiApiKey,
|
||||
geminiBaseUrl: config.geminiBaseUrl,
|
||||
litellmBaseUrl: config.liteLlmBaseUrl,
|
||||
asksageApiUrl: config.asksageApiUrl,
|
||||
|
||||
// LiteLLM specific fields
|
||||
litellmApiKey: config.liteLlmApiKey,
|
||||
litellmUsePromptCache: config.liteLlmUsePromptCache,
|
||||
|
||||
// Model configuration
|
||||
thinkingBudgetTokens: config.thinkingBudgetTokens ? Number(config.thinkingBudgetTokens) : undefined,
|
||||
reasoningEffort: config.reasoningEffort,
|
||||
requestTimeoutMs: config.requestTimeoutMs ? Number(config.requestTimeoutMs) : undefined,
|
||||
|
||||
// Fireworks specific
|
||||
openaiNativeApiKey: config.openAiNativeApiKey,
|
||||
deepSeekApiKey: config.deepSeekApiKey,
|
||||
requestyApiKey: config.requestyApiKey,
|
||||
togetherApiKey: config.togetherApiKey,
|
||||
fireworksApiKey: config.fireworksApiKey,
|
||||
fireworksModelMaxCompletionTokens: config.fireworksModelMaxCompletionTokens
|
||||
? Number(config.fireworksModelMaxCompletionTokens)
|
||||
: undefined,
|
||||
fireworksModelMaxTokens: config.fireworksModelMaxTokens ? Number(config.fireworksModelMaxTokens) : undefined,
|
||||
|
||||
// Azure specific
|
||||
qwenApiKey: config.qwenApiKey,
|
||||
doubaoApiKey: config.doubaoApiKey,
|
||||
mistralApiKey: config.mistralApiKey,
|
||||
moonshotApiKey: config.moonshotApiKey,
|
||||
azureApiVersion: config.azureApiVersion,
|
||||
|
||||
// Ollama specific
|
||||
ollamaApiOptionsCtxNum: config.ollamaApiOptionsCtxNum,
|
||||
|
||||
// Qwen specific
|
||||
qwenApiLine: config.qwenApiLine,
|
||||
|
||||
// Moonshot specific
|
||||
moonshotApiLine: config.moonshotApiLine,
|
||||
|
||||
// OpenRouter specific
|
||||
openrouterProviderSorting: config.openRouterProviderSorting,
|
||||
|
||||
// SAP AI Core specific
|
||||
nebiusApiKey: config.nebiusApiKey,
|
||||
asksageApiUrl: config.asksageApiUrl,
|
||||
asksageApiKey: config.asksageApiKey,
|
||||
xaiApiKey: config.xaiApiKey,
|
||||
sambanovaApiKey: config.sambanovaApiKey,
|
||||
cerebrasApiKey: config.cerebrasApiKey,
|
||||
requestTimeoutMs: config.requestTimeoutMs ? Number(config.requestTimeoutMs) : undefined,
|
||||
sapAiCoreClientId: config.sapAiCoreClientId,
|
||||
sapAiCoreClientSecret: config.sapAiCoreClientSecret,
|
||||
sapAiCoreBaseUrl: config.sapAiCoreBaseUrl,
|
||||
sapAiCoreTokenUrl: config.sapAiCoreTokenUrl,
|
||||
sapAiResourceGroup: config.sapAiResourceGroup,
|
||||
sapAiCoreTokenUrl: config.sapAiCoreTokenUrl,
|
||||
sapAiCoreBaseUrl: config.sapAiCoreBaseUrl,
|
||||
|
||||
// Complex objects stored as JSON strings
|
||||
vscodeLmModelSelector: config.vsCodeLmModelSelector ? JSON.stringify(config.vsCodeLmModelSelector) : undefined,
|
||||
openrouterModelInfo: config.openRouterModelInfo ? JSON.stringify(config.openRouterModelInfo) : undefined,
|
||||
openaiModelInfo: config.openAiModelInfo ? JSON.stringify(config.openAiModelInfo) : undefined,
|
||||
requestyModelInfo: config.requestyModelInfo ? JSON.stringify(config.requestyModelInfo) : undefined,
|
||||
litellmModelInfo: config.liteLlmModelInfo ? JSON.stringify(config.liteLlmModelInfo) : undefined,
|
||||
openaiHeaders: config.openAiHeaders ? JSON.stringify(config.openAiHeaders) : undefined,
|
||||
// Plan mode configurations
|
||||
planModeApiProvider: config.planModeApiProvider,
|
||||
planModeApiModelId: config.planModeApiModelId,
|
||||
planModeThinkingBudgetTokens: config.planModeThinkingBudgetTokens
|
||||
? Number(config.planModeThinkingBudgetTokens)
|
||||
: undefined,
|
||||
planModeReasoningEffort: config.planModeReasoningEffort,
|
||||
planModeVscodeLmModelSelector: config.planModeVsCodeLmModelSelector
|
||||
? JSON.stringify(config.planModeVsCodeLmModelSelector)
|
||||
: undefined,
|
||||
planModeAwsBedrockCustomSelected: config.planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId: config.planModeAwsBedrockCustomModelBaseId,
|
||||
planModeOpenrouterModelId: config.planModeOpenRouterModelId,
|
||||
planModeOpenrouterModelInfo: config.planModeOpenRouterModelInfo
|
||||
? JSON.stringify(config.planModeOpenRouterModelInfo)
|
||||
: undefined,
|
||||
planModeOpenaiModelId: config.planModeOpenAiModelId,
|
||||
planModeOpenaiModelInfo: config.planModeOpenAiModelInfo ? JSON.stringify(config.planModeOpenAiModelInfo) : undefined,
|
||||
planModeOllamaModelId: config.planModeOllamaModelId,
|
||||
planModeLmStudioModelId: config.planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId: config.planModeLiteLlmModelId,
|
||||
planModeLiteLlmModelInfo: config.planModeLiteLlmModelInfo ? JSON.stringify(config.planModeLiteLlmModelInfo) : undefined,
|
||||
planModeRequestyModelId: config.planModeRequestyModelId,
|
||||
planModeRequestyModelInfo: config.planModeRequestyModelInfo
|
||||
? JSON.stringify(config.planModeRequestyModelInfo)
|
||||
: undefined,
|
||||
planModeTogetherModelId: config.planModeTogetherModelId,
|
||||
planModeFireworksModelId: config.planModeFireworksModelId,
|
||||
planModeSapAiCoreModelId: config.planModeSapAiCoreModelId,
|
||||
|
||||
// Claude Code specific
|
||||
claudeCodePath: config.claudeCodePath,
|
||||
// Act mode configurations
|
||||
actModeApiProvider: config.actModeApiProvider,
|
||||
actModeApiModelId: config.actModeApiModelId,
|
||||
actModeThinkingBudgetTokens: config.actModeThinkingBudgetTokens ? Number(config.actModeThinkingBudgetTokens) : undefined,
|
||||
actModeReasoningEffort: config.actModeReasoningEffort,
|
||||
actModeVscodeLmModelSelector: config.actModeVsCodeLmModelSelector
|
||||
? JSON.stringify(config.actModeVsCodeLmModelSelector)
|
||||
: undefined,
|
||||
actModeAwsBedrockCustomSelected: config.actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId: config.actModeAwsBedrockCustomModelBaseId,
|
||||
actModeOpenrouterModelId: config.actModeOpenRouterModelId,
|
||||
actModeOpenrouterModelInfo: config.actModeOpenRouterModelInfo
|
||||
? JSON.stringify(config.actModeOpenRouterModelInfo)
|
||||
: undefined,
|
||||
actModeOpenaiModelId: config.actModeOpenAiModelId,
|
||||
actModeOpenaiModelInfo: config.actModeOpenAiModelInfo ? JSON.stringify(config.actModeOpenAiModelInfo) : undefined,
|
||||
actModeOllamaModelId: config.actModeOllamaModelId,
|
||||
actModeLmStudioModelId: config.actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId: config.actModeLiteLlmModelId,
|
||||
actModeLiteLlmModelInfo: config.actModeLiteLlmModelInfo ? JSON.stringify(config.actModeLiteLlmModelInfo) : undefined,
|
||||
actModeRequestyModelId: config.actModeRequestyModelId,
|
||||
actModeRequestyModelInfo: config.actModeRequestyModelInfo ? JSON.stringify(config.actModeRequestyModelInfo) : undefined,
|
||||
actModeTogetherModelId: config.actModeTogetherModelId,
|
||||
actModeFireworksModelId: config.actModeFireworksModelId,
|
||||
actModeSapAiCoreModelId: config.actModeSapAiCoreModelId,
|
||||
|
||||
// Arrays
|
||||
// Favorited model IDs
|
||||
favoritedModelIds: config.favoritedModelIds || [],
|
||||
})
|
||||
}
|
||||
@@ -137,45 +138,16 @@ export function convertApiConfigurationToProtoApiConfiguration(config: ApiConfig
|
||||
export function convertProtoApiConfigurationToApiConfiguration(protoConfig: ProtoApiConfiguration): ApiConfiguration {
|
||||
// eslint-disable-next-line eslint-rules/no-protobuf-object-literals
|
||||
const config: ApiConfiguration = {
|
||||
// Core API fields
|
||||
apiProvider: protoConfig.apiProvider as ApiProvider,
|
||||
apiModelId: protoConfig.apiModelId,
|
||||
// Global configuration fields (not mode-specific)
|
||||
apiKey: protoConfig.apiKey,
|
||||
|
||||
// Provider-specific API keys
|
||||
clineAccountId: protoConfig.clineAccountId,
|
||||
openRouterApiKey: protoConfig.openrouterApiKey,
|
||||
taskId: protoConfig.taskId,
|
||||
liteLlmBaseUrl: protoConfig.liteLlmBaseUrl,
|
||||
liteLlmApiKey: protoConfig.liteLlmApiKey,
|
||||
liteLlmUsePromptCache: protoConfig.liteLlmUsePromptCache,
|
||||
anthropicBaseUrl: protoConfig.anthropicBaseUrl,
|
||||
openAiApiKey: protoConfig.openaiApiKey,
|
||||
openAiNativeApiKey: protoConfig.openaiNativeApiKey,
|
||||
geminiApiKey: protoConfig.geminiApiKey,
|
||||
deepSeekApiKey: protoConfig.deepseekApiKey,
|
||||
requestyApiKey: protoConfig.requestyApiKey,
|
||||
togetherApiKey: protoConfig.togetherApiKey,
|
||||
fireworksApiKey: protoConfig.fireworksApiKey,
|
||||
qwenApiKey: protoConfig.qwenApiKey,
|
||||
doubaoApiKey: protoConfig.doubaoApiKey,
|
||||
mistralApiKey: protoConfig.mistralApiKey,
|
||||
moonshotApiKey: protoConfig.moonshotApiKey,
|
||||
nebiusApiKey: protoConfig.nebiusApiKey,
|
||||
asksageApiKey: protoConfig.asksageApiKey,
|
||||
xaiApiKey: protoConfig.xaiApiKey,
|
||||
sambanovaApiKey: protoConfig.sambanovaApiKey,
|
||||
cerebrasApiKey: protoConfig.cerebrasApiKey,
|
||||
|
||||
// Model IDs
|
||||
openRouterModelId: protoConfig.openrouterModelId,
|
||||
openAiModelId: protoConfig.openaiModelId,
|
||||
ollamaModelId: protoConfig.ollamaModelId,
|
||||
lmStudioModelId: protoConfig.lmStudioModelId,
|
||||
liteLlmModelId: protoConfig.litellmModelId,
|
||||
requestyModelId: protoConfig.requestyModelId,
|
||||
togetherModelId: protoConfig.togetherModelId,
|
||||
fireworksModelId: protoConfig.fireworksModelId,
|
||||
|
||||
// AWS Bedrock fields
|
||||
awsBedrockCustomSelected: protoConfig.awsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId: protoConfig.awsBedrockCustomModelBaseId as BedrockModelId | undefined,
|
||||
openRouterApiKey: protoConfig.openrouterApiKey,
|
||||
openRouterProviderSorting: protoConfig.openrouterProviderSorting,
|
||||
awsAccessKey: protoConfig.awsAccessKey,
|
||||
awsSecretKey: protoConfig.awsSecretKey,
|
||||
awsSessionToken: protoConfig.awsSessionToken,
|
||||
@@ -187,83 +159,121 @@ export function convertProtoApiConfigurationToApiConfiguration(protoConfig: Prot
|
||||
awsAuthentication: protoConfig.awsAuthentication,
|
||||
awsBedrockApiKey: protoConfig.awsBedrockApiKey,
|
||||
awsBedrockEndpoint: protoConfig.awsBedrockEndpoint,
|
||||
|
||||
// Vertex AI fields
|
||||
claudeCodePath: protoConfig.claudeCodePath,
|
||||
vertexProjectId: protoConfig.vertexProjectId,
|
||||
vertexRegion: protoConfig.vertexRegion,
|
||||
|
||||
// Base URLs and endpoints
|
||||
openAiBaseUrl: protoConfig.openaiBaseUrl,
|
||||
openAiApiKey: protoConfig.openaiApiKey,
|
||||
ollamaBaseUrl: protoConfig.ollamaBaseUrl,
|
||||
ollamaApiOptionsCtxNum: protoConfig.ollamaApiOptionsCtxNum,
|
||||
lmStudioBaseUrl: protoConfig.lmStudioBaseUrl,
|
||||
geminiApiKey: protoConfig.geminiApiKey,
|
||||
geminiBaseUrl: protoConfig.geminiBaseUrl,
|
||||
liteLlmBaseUrl: protoConfig.litellmBaseUrl,
|
||||
asksageApiUrl: protoConfig.asksageApiUrl,
|
||||
|
||||
// LiteLLM specific fields
|
||||
liteLlmApiKey: protoConfig.litellmApiKey,
|
||||
liteLlmUsePromptCache: protoConfig.litellmUsePromptCache,
|
||||
|
||||
// Model configuration
|
||||
thinkingBudgetTokens: protoConfig.thinkingBudgetTokens ? Number(protoConfig.thinkingBudgetTokens) : undefined,
|
||||
reasoningEffort: protoConfig.reasoningEffort,
|
||||
requestTimeoutMs: protoConfig.requestTimeoutMs ? Number(protoConfig.requestTimeoutMs) : undefined,
|
||||
|
||||
// Fireworks specific
|
||||
openAiNativeApiKey: protoConfig.openaiNativeApiKey,
|
||||
deepSeekApiKey: protoConfig.deepSeekApiKey,
|
||||
requestyApiKey: protoConfig.requestyApiKey,
|
||||
togetherApiKey: protoConfig.togetherApiKey,
|
||||
fireworksApiKey: protoConfig.fireworksApiKey,
|
||||
fireworksModelMaxCompletionTokens: protoConfig.fireworksModelMaxCompletionTokens
|
||||
? Number(protoConfig.fireworksModelMaxCompletionTokens)
|
||||
: undefined,
|
||||
fireworksModelMaxTokens: protoConfig.fireworksModelMaxTokens ? Number(protoConfig.fireworksModelMaxTokens) : undefined,
|
||||
|
||||
// Azure specific
|
||||
qwenApiKey: protoConfig.qwenApiKey,
|
||||
doubaoApiKey: protoConfig.doubaoApiKey,
|
||||
mistralApiKey: protoConfig.mistralApiKey,
|
||||
moonshotApiKey: protoConfig.moonshotApiKey,
|
||||
azureApiVersion: protoConfig.azureApiVersion,
|
||||
|
||||
// Ollama specific
|
||||
ollamaApiOptionsCtxNum: protoConfig.ollamaApiOptionsCtxNum,
|
||||
|
||||
// Qwen specific
|
||||
qwenApiLine: protoConfig.qwenApiLine,
|
||||
|
||||
// Moonshot specific
|
||||
moonshotApiLine: protoConfig.moonshotApiLine,
|
||||
|
||||
// OpenRouter specific
|
||||
openRouterProviderSorting: protoConfig.openrouterProviderSorting,
|
||||
|
||||
// SAP AI Core specific
|
||||
nebiusApiKey: protoConfig.nebiusApiKey,
|
||||
asksageApiUrl: protoConfig.asksageApiUrl,
|
||||
asksageApiKey: protoConfig.asksageApiKey,
|
||||
xaiApiKey: protoConfig.xaiApiKey,
|
||||
sambanovaApiKey: protoConfig.sambanovaApiKey,
|
||||
cerebrasApiKey: protoConfig.cerebrasApiKey,
|
||||
requestTimeoutMs: protoConfig.requestTimeoutMs ? Number(protoConfig.requestTimeoutMs) : undefined,
|
||||
sapAiCoreClientId: protoConfig.sapAiCoreClientId,
|
||||
sapAiCoreClientSecret: protoConfig.sapAiCoreClientSecret,
|
||||
sapAiCoreBaseUrl: protoConfig.sapAiCoreBaseUrl,
|
||||
sapAiCoreTokenUrl: protoConfig.sapAiCoreTokenUrl,
|
||||
sapAiResourceGroup: protoConfig.sapAiResourceGroup,
|
||||
sapAiCoreTokenUrl: protoConfig.sapAiCoreTokenUrl,
|
||||
sapAiCoreBaseUrl: protoConfig.sapAiCoreBaseUrl,
|
||||
|
||||
// Claude Code specific
|
||||
claudeCodePath: protoConfig.claudeCodePath,
|
||||
// Plan mode configurations
|
||||
planModeApiProvider: protoConfig.planModeApiProvider as ApiProvider,
|
||||
planModeApiModelId: protoConfig.planModeApiModelId,
|
||||
planModeThinkingBudgetTokens: protoConfig.planModeThinkingBudgetTokens
|
||||
? Number(protoConfig.planModeThinkingBudgetTokens)
|
||||
: undefined,
|
||||
planModeReasoningEffort: protoConfig.planModeReasoningEffort,
|
||||
planModeAwsBedrockCustomSelected: protoConfig.planModeAwsBedrockCustomSelected,
|
||||
planModeAwsBedrockCustomModelBaseId: protoConfig.planModeAwsBedrockCustomModelBaseId as BedrockModelId | undefined,
|
||||
planModeOpenRouterModelId: protoConfig.planModeOpenrouterModelId,
|
||||
planModeOpenAiModelId: protoConfig.planModeOpenaiModelId,
|
||||
planModeOllamaModelId: protoConfig.planModeOllamaModelId,
|
||||
planModeLmStudioModelId: protoConfig.planModeLmStudioModelId,
|
||||
planModeLiteLlmModelId: protoConfig.planModeLiteLlmModelId,
|
||||
planModeRequestyModelId: protoConfig.planModeRequestyModelId,
|
||||
planModeTogetherModelId: protoConfig.planModeTogetherModelId,
|
||||
planModeFireworksModelId: protoConfig.planModeFireworksModelId,
|
||||
planModeSapAiCoreModelId: protoConfig.planModeSapAiCoreModelId,
|
||||
|
||||
// Arrays
|
||||
// Act mode configurations
|
||||
actModeApiProvider: protoConfig.actModeApiProvider as ApiProvider,
|
||||
actModeApiModelId: protoConfig.actModeApiModelId,
|
||||
actModeThinkingBudgetTokens: protoConfig.actModeThinkingBudgetTokens
|
||||
? Number(protoConfig.actModeThinkingBudgetTokens)
|
||||
: undefined,
|
||||
actModeReasoningEffort: protoConfig.actModeReasoningEffort,
|
||||
actModeAwsBedrockCustomSelected: protoConfig.actModeAwsBedrockCustomSelected,
|
||||
actModeAwsBedrockCustomModelBaseId: protoConfig.actModeAwsBedrockCustomModelBaseId as BedrockModelId | undefined,
|
||||
actModeOpenRouterModelId: protoConfig.actModeOpenrouterModelId,
|
||||
actModeOpenAiModelId: protoConfig.actModeOpenaiModelId,
|
||||
actModeOllamaModelId: protoConfig.actModeOllamaModelId,
|
||||
actModeLmStudioModelId: protoConfig.actModeLmStudioModelId,
|
||||
actModeLiteLlmModelId: protoConfig.actModeLiteLlmModelId,
|
||||
actModeRequestyModelId: protoConfig.actModeRequestyModelId,
|
||||
actModeTogetherModelId: protoConfig.actModeTogetherModelId,
|
||||
actModeFireworksModelId: protoConfig.actModeFireworksModelId,
|
||||
actModeSapAiCoreModelId: protoConfig.actModeSapAiCoreModelId,
|
||||
|
||||
// Favorited model IDs
|
||||
favoritedModelIds: protoConfig.favoritedModelIds || [],
|
||||
}
|
||||
|
||||
// Handle complex JSON objects
|
||||
try {
|
||||
if (protoConfig.vscodeLmModelSelector) {
|
||||
config.vsCodeLmModelSelector = JSON.parse(protoConfig.vscodeLmModelSelector)
|
||||
}
|
||||
if (protoConfig.openrouterModelInfo) {
|
||||
config.openRouterModelInfo = JSON.parse(protoConfig.openrouterModelInfo)
|
||||
}
|
||||
if (protoConfig.openaiModelInfo) {
|
||||
config.openAiModelInfo = JSON.parse(protoConfig.openaiModelInfo)
|
||||
}
|
||||
if (protoConfig.requestyModelInfo) {
|
||||
config.requestyModelInfo = JSON.parse(protoConfig.requestyModelInfo)
|
||||
}
|
||||
if (protoConfig.litellmModelInfo) {
|
||||
config.liteLlmModelInfo = JSON.parse(protoConfig.litellmModelInfo)
|
||||
}
|
||||
if (protoConfig.openaiHeaders) {
|
||||
config.openAiHeaders = JSON.parse(protoConfig.openaiHeaders)
|
||||
}
|
||||
if (protoConfig.planModeVscodeLmModelSelector) {
|
||||
config.planModeVsCodeLmModelSelector = JSON.parse(protoConfig.planModeVscodeLmModelSelector)
|
||||
}
|
||||
if (protoConfig.planModeOpenrouterModelInfo) {
|
||||
config.planModeOpenRouterModelInfo = JSON.parse(protoConfig.planModeOpenrouterModelInfo)
|
||||
}
|
||||
if (protoConfig.planModeOpenaiModelInfo) {
|
||||
config.planModeOpenAiModelInfo = JSON.parse(protoConfig.planModeOpenaiModelInfo)
|
||||
}
|
||||
if (protoConfig.planModeLiteLlmModelInfo) {
|
||||
config.planModeLiteLlmModelInfo = JSON.parse(protoConfig.planModeLiteLlmModelInfo)
|
||||
}
|
||||
if (protoConfig.planModeRequestyModelInfo) {
|
||||
config.planModeRequestyModelInfo = JSON.parse(protoConfig.planModeRequestyModelInfo)
|
||||
}
|
||||
if (protoConfig.actModeVscodeLmModelSelector) {
|
||||
config.actModeVsCodeLmModelSelector = JSON.parse(protoConfig.actModeVscodeLmModelSelector)
|
||||
}
|
||||
if (protoConfig.actModeOpenrouterModelInfo) {
|
||||
config.actModeOpenRouterModelInfo = JSON.parse(protoConfig.actModeOpenrouterModelInfo)
|
||||
}
|
||||
if (protoConfig.actModeOpenaiModelInfo) {
|
||||
config.actModeOpenAiModelInfo = JSON.parse(protoConfig.actModeOpenaiModelInfo)
|
||||
}
|
||||
if (protoConfig.actModeLiteLlmModelInfo) {
|
||||
config.actModeLiteLlmModelInfo = JSON.parse(protoConfig.actModeLiteLlmModelInfo)
|
||||
}
|
||||
if (protoConfig.actModeRequestyModelInfo) {
|
||||
config.actModeRequestyModelInfo = JSON.parse(protoConfig.actModeRequestyModelInfo)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to parse complex JSON objects in API configuration:", error)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { CODE_BLOCK_BG_COLOR } from "@/components/common/CodeBlock"
|
||||
import Thumbnails from "@/components/common/Thumbnails"
|
||||
import Tooltip from "@/components/common/Tooltip"
|
||||
import ApiOptions from "@/components/settings/ApiOptions"
|
||||
import { normalizeApiConfiguration } from "@/components/settings/utils/providerUtils"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "@/components/settings/utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { FileServiceClient, StateServiceClient, ModelsServiceClient } from "@/services/grpc-client"
|
||||
import {
|
||||
@@ -966,8 +966,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
|
||||
// Separate the API config submission logic
|
||||
const submitApiConfig = useCallback(async () => {
|
||||
const apiValidationResult = validateApiConfiguration(apiConfiguration)
|
||||
const modelIdValidationResult = validateModelId(apiConfiguration, openRouterModels)
|
||||
const apiValidationResult = validateApiConfiguration(chatSettings.mode, apiConfiguration)
|
||||
const modelIdValidationResult = validateModelId(chatSettings.mode, apiConfiguration, openRouterModels)
|
||||
|
||||
if (!apiValidationResult && !modelIdValidationResult && apiConfiguration) {
|
||||
try {
|
||||
@@ -1089,7 +1089,16 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
|
||||
// Get model display name
|
||||
const modelDisplayName = useMemo(() => {
|
||||
const { selectedProvider, selectedModelId } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedProvider, selectedModelId } = normalizeApiConfiguration(apiConfiguration, chatSettings.mode)
|
||||
const {
|
||||
vsCodeLmModelSelector,
|
||||
togetherModelId,
|
||||
fireworksModelId,
|
||||
lmStudioModelId,
|
||||
ollamaModelId,
|
||||
liteLlmModelId,
|
||||
requestyModelId,
|
||||
} = getModeSpecificFields(apiConfiguration, chatSettings.mode)
|
||||
const unknownModel = "unknown"
|
||||
if (!apiConfiguration) return unknownModel
|
||||
switch (selectedProvider) {
|
||||
@@ -1098,25 +1107,25 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
case "openai":
|
||||
return `openai-compat:${selectedModelId}`
|
||||
case "vscode-lm":
|
||||
return `vscode-lm:${apiConfiguration.vsCodeLmModelSelector ? `${apiConfiguration.vsCodeLmModelSelector.vendor ?? ""}/${apiConfiguration.vsCodeLmModelSelector.family ?? ""}` : unknownModel}`
|
||||
return `vscode-lm:${vsCodeLmModelSelector ? `${vsCodeLmModelSelector.vendor ?? ""}/${vsCodeLmModelSelector.family ?? ""}` : unknownModel}`
|
||||
case "together":
|
||||
return `${selectedProvider}:${apiConfiguration.togetherModelId}`
|
||||
return `${selectedProvider}:${togetherModelId}`
|
||||
case "fireworks":
|
||||
return `fireworks:${apiConfiguration.fireworksModelId}`
|
||||
return `fireworks:${fireworksModelId}`
|
||||
case "lmstudio":
|
||||
return `${selectedProvider}:${apiConfiguration.lmStudioModelId}`
|
||||
return `${selectedProvider}:${lmStudioModelId}`
|
||||
case "ollama":
|
||||
return `${selectedProvider}:${apiConfiguration.ollamaModelId}`
|
||||
return `${selectedProvider}:${ollamaModelId}`
|
||||
case "litellm":
|
||||
return `${selectedProvider}:${apiConfiguration.liteLlmModelId}`
|
||||
return `${selectedProvider}:${liteLlmModelId}`
|
||||
case "requesty":
|
||||
return `${selectedProvider}:${apiConfiguration.requestyModelId}`
|
||||
return `${selectedProvider}:${requestyModelId}`
|
||||
case "anthropic":
|
||||
case "openrouter":
|
||||
default:
|
||||
return `${selectedProvider}:${selectedModelId}`
|
||||
}
|
||||
}, [apiConfiguration])
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
|
||||
// Calculate arrow position and menu position based on button location
|
||||
useEffect(() => {
|
||||
@@ -1720,7 +1729,13 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
||||
style={{
|
||||
bottom: `calc(100vh - ${menuPosition}px + 6px)`,
|
||||
}}>
|
||||
<ApiOptions showModelOptions={true} modelIdErrorMessage={undefined} isPopup={true} />
|
||||
<ApiOptions
|
||||
showModelOptions={true}
|
||||
apiErrorMessage={undefined}
|
||||
modelIdErrorMessage={undefined}
|
||||
isPopup={true}
|
||||
currentMode={chatSettings.mode}
|
||||
/>
|
||||
</ModelSelectorTooltip>
|
||||
)}
|
||||
</ModelContainer>
|
||||
|
||||
@@ -47,6 +47,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
||||
apiConfiguration,
|
||||
telemetrySetting,
|
||||
navigateToChat,
|
||||
chatSettings,
|
||||
} = 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
|
||||
@@ -199,8 +200,8 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
||||
messageHandlers
|
||||
|
||||
const { selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
return normalizeApiConfiguration(apiConfiguration, chatSettings.mode)
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
|
||||
const selectFilesAndImages = useCallback(async () => {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import HeroTooltip from "@/components/common/HeroTooltip"
|
||||
import Thumbnails from "@/components/common/Thumbnails"
|
||||
import { normalizeApiConfiguration } from "@/components/settings/utils/providerUtils"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "@/components/settings/utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { FileServiceClient, TaskServiceClient, UiServiceClient } from "@/services/grpc-client"
|
||||
import { formatLargeNumber, formatSize } from "@/utils/format"
|
||||
@@ -43,7 +43,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
onClose,
|
||||
onScrollToMessage,
|
||||
}) => {
|
||||
const { apiConfiguration, currentTaskItem, checkpointTrackerErrorMessage, clineMessages, navigateToSettings } =
|
||||
const { apiConfiguration, currentTaskItem, checkpointTrackerErrorMessage, clineMessages, navigateToSettings, chatSettings } =
|
||||
useExtensionState()
|
||||
const [isTaskExpanded, setIsTaskExpanded] = useState(true)
|
||||
const [isTextExpanded, setIsTextExpanded] = useState(false)
|
||||
@@ -51,7 +51,10 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
const textContainerRef = useRef<HTMLDivElement>(null)
|
||||
const textRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const { selectedModelInfo } = useMemo(() => normalizeApiConfiguration(apiConfiguration), [apiConfiguration])
|
||||
const { selectedModelInfo } = useMemo(
|
||||
() => normalizeApiConfiguration(apiConfiguration, chatSettings.mode),
|
||||
[apiConfiguration, chatSettings.mode],
|
||||
)
|
||||
const contextWindow = selectedModelInfo?.contextWindow
|
||||
|
||||
// Open task header when checkpoint tracker error message is set
|
||||
@@ -130,19 +133,18 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
||||
}, [task.text, windowWidth, isTaskExpanded])
|
||||
|
||||
const isCostAvailable = useMemo(() => {
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, chatSettings.mode)
|
||||
const openAiCompatHasPricing =
|
||||
apiConfiguration?.apiProvider === "openai" &&
|
||||
apiConfiguration?.openAiModelInfo?.inputPrice &&
|
||||
apiConfiguration?.openAiModelInfo?.outputPrice
|
||||
modeFields.apiProvider === "openai" &&
|
||||
modeFields.openAiModelInfo?.inputPrice &&
|
||||
modeFields.openAiModelInfo?.outputPrice
|
||||
if (openAiCompatHasPricing) {
|
||||
return true
|
||||
}
|
||||
return (
|
||||
apiConfiguration?.apiProvider !== "vscode-lm" &&
|
||||
apiConfiguration?.apiProvider !== "ollama" &&
|
||||
apiConfiguration?.apiProvider !== "lmstudio"
|
||||
modeFields.apiProvider !== "vscode-lm" && modeFields.apiProvider !== "ollama" && modeFields.apiProvider !== "lmstudio"
|
||||
)
|
||||
}, [apiConfiguration?.apiProvider, apiConfiguration?.openAiModelInfo])
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
|
||||
const shouldShowPromptCacheInfo = () => {
|
||||
// Hybrid logic: Show cache info if we have actual cache data,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { ModelsServiceClient, StateServiceClient } from "@/services/grpc-client"
|
||||
import { BooleanRequest, StringRequest } from "@shared/proto/common"
|
||||
import { VSCodeButton, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import { ModelsServiceClient } from "@/services/grpc-client"
|
||||
import { StringRequest } from "@shared/proto/common"
|
||||
import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import { useInterval } from "react-use"
|
||||
import styled from "styled-components"
|
||||
import { OPENROUTER_MODEL_PICKER_Z_INDEX } from "./OpenRouterModelPicker"
|
||||
|
||||
import { normalizeApiConfiguration } from "@/components/settings/utils/providerUtils"
|
||||
import { ClineProvider } from "./providers/ClineProvider"
|
||||
import { OpenRouterProvider } from "./providers/OpenRouterProvider"
|
||||
import { MistralProvider } from "./providers/MistralProvider"
|
||||
@@ -37,13 +37,14 @@ 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"
|
||||
|
||||
interface ApiOptionsProps {
|
||||
showSubmitButton?: boolean
|
||||
showModelOptions: boolean
|
||||
apiErrorMessage?: string
|
||||
modelIdErrorMessage?: string
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
// This is necessary to ensure dropdown opens downward, important for when this is used in popup
|
||||
@@ -70,24 +71,16 @@ declare module "vscode" {
|
||||
}
|
||||
}
|
||||
|
||||
const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, isPopup, showSubmitButton }: ApiOptionsProps) => {
|
||||
const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, isPopup, currentMode }: ApiOptionsProps) => {
|
||||
// Use full context state for immediate save payload
|
||||
const { apiConfiguration, uriScheme } = useExtensionState()
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
|
||||
const selectedProvider = apiConfiguration?.apiProvider
|
||||
const { selectedProvider } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const [ollamaModels, setOllamaModels] = useState<string[]>([])
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await StateServiceClient.setWelcomeViewCompleted(BooleanRequest.create({ value: true }))
|
||||
} catch (error) {
|
||||
console.error("Failed to update API configuration or complete welcome view:", error)
|
||||
}
|
||||
}
|
||||
|
||||
// Poll ollama/vscode-lm models
|
||||
const requestLocalModels = useCallback(async () => {
|
||||
if (selectedProvider === "ollama") {
|
||||
@@ -132,7 +125,11 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
|
||||
id="api-provider"
|
||||
value={selectedProvider}
|
||||
onChange={(e: any) => {
|
||||
handleFieldChange("apiProvider", e.target.value)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiProvider", act: "actModeApiProvider" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}}
|
||||
style={{
|
||||
minWidth: 130,
|
||||
@@ -143,13 +140,13 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
|
||||
<VSCodeOption value="anthropic">Anthropic</VSCodeOption>
|
||||
<VSCodeOption value="claude-code">Claude Code</VSCodeOption>
|
||||
<VSCodeOption value="bedrock">Amazon Bedrock</VSCodeOption>
|
||||
<VSCodeOption value="openai-native">OpenAI</VSCodeOption>
|
||||
<VSCodeOption value="openai">OpenAI Compatible</VSCodeOption>
|
||||
<VSCodeOption value="vertex">GCP Vertex AI</VSCodeOption>
|
||||
<VSCodeOption value="gemini">Google Gemini</VSCodeOption>
|
||||
<VSCodeOption value="groq">Groq</VSCodeOption>
|
||||
<VSCodeOption value="deepseek">DeepSeek</VSCodeOption>
|
||||
<VSCodeOption value="openai">OpenAI Compatible</VSCodeOption>
|
||||
<VSCodeOption value="mistral">Mistral</VSCodeOption>
|
||||
<VSCodeOption value="openai-native">OpenAI</VSCodeOption>
|
||||
<VSCodeOption value="vscode-lm">VS Code LM API</VSCodeOption>
|
||||
<VSCodeOption value="requesty">Requesty</VSCodeOption>
|
||||
<VSCodeOption value="fireworks">Fireworks</VSCodeOption>
|
||||
@@ -171,116 +168,116 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
|
||||
</DropdownContainer>
|
||||
|
||||
{apiConfiguration && selectedProvider === "cline" && (
|
||||
<ClineProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<ClineProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "asksage" && (
|
||||
<AskSageProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<AskSageProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "anthropic" && (
|
||||
<AnthropicProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<AnthropicProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "claude-code" && (
|
||||
<ClaudeCodeProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<ClaudeCodeProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "openai-native" && (
|
||||
<OpenAINativeProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<OpenAINativeProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "qwen" && (
|
||||
<QwenProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<QwenProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "doubao" && (
|
||||
<DoubaoProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<DoubaoProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "mistral" && (
|
||||
<MistralProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<MistralProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "openrouter" && (
|
||||
<OpenRouterProvider showModelOptions={showModelOptions} isPopup={isPopup} uriScheme={uriScheme} />
|
||||
<OpenRouterProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "deepseek" && (
|
||||
<DeepSeekProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<DeepSeekProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "together" && (
|
||||
<TogetherProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<TogetherProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "openai" && (
|
||||
<OpenAICompatibleProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<OpenAICompatibleProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "sambanova" && (
|
||||
<SambanovaProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<SambanovaProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "bedrock" && (
|
||||
<BedrockProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<BedrockProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "vertex" && (
|
||||
<VertexProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<VertexProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "gemini" && (
|
||||
<GeminiProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<GeminiProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "requesty" && (
|
||||
<RequestyProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<RequestyProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "fireworks" && (
|
||||
<FireworksProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<FireworksProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "vscode-lm" && <VSCodeLmProvider />}
|
||||
{apiConfiguration && selectedProvider === "vscode-lm" && <VSCodeLmProvider currentMode={currentMode} />}
|
||||
|
||||
{apiConfiguration && selectedProvider === "groq" && (
|
||||
<GroqProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<GroqProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
{apiConfiguration && selectedProvider === "litellm" && (
|
||||
<LiteLlmProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<LiteLlmProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "lmstudio" && (
|
||||
<LMStudioProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<LMStudioProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "ollama" && (
|
||||
<OllamaProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<OllamaProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "moonshot" && (
|
||||
<MoonshotProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<MoonshotProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "huggingface" && (
|
||||
<HuggingFaceProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<HuggingFaceProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "nebius" && (
|
||||
<NebiusProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<NebiusProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "xai" && (
|
||||
<XaiProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<XaiProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "cerebras" && (
|
||||
<CerebrasProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<CerebrasProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiConfiguration && selectedProvider === "sapaicore" && (
|
||||
<SapAiCoreProvider showModelOptions={showModelOptions} isPopup={isPopup} />
|
||||
<SapAiCoreProvider showModelOptions={showModelOptions} isPopup={isPopup} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
{apiErrorMessage && (
|
||||
@@ -303,12 +300,6 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
|
||||
{modelIdErrorMessage}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{showSubmitButton && (
|
||||
<VSCodeButton onClick={handleSubmit} disabled={apiErrorMessage != null} className="mt-0.75" title="Submit">
|
||||
Let's go!
|
||||
</VSCodeButton>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,15 +12,19 @@ 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"
|
||||
|
||||
export interface GroqModelPickerProps {
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
const GroqModelPicker: React.FC<GroqModelPickerProps> = ({ isPopup }) => {
|
||||
const GroqModelPicker: React.FC<GroqModelPickerProps> = ({ isPopup, currentMode }) => {
|
||||
const { apiConfiguration, groqModels: dynamicGroqModels, setGroqModels } = useExtensionState()
|
||||
const { handleFieldsChange } = useApiConfigurationHandlers()
|
||||
const [searchTerm, setSearchTerm] = useState(apiConfiguration?.groqModelId || groqDefaultModelId)
|
||||
const { handleModeFieldsChange } = useApiConfigurationHandlers()
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
const [searchTerm, setSearchTerm] = useState(modeFields.groqModelId || groqDefaultModelId)
|
||||
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm)
|
||||
const [isDropdownVisible, setIsDropdownVisible] = useState(false)
|
||||
const [selectedIndex, setSelectedIndex] = useState(-1)
|
||||
@@ -32,16 +36,23 @@ const GroqModelPicker: React.FC<GroqModelPickerProps> = ({ isPopup }) => {
|
||||
// Use dynamic models if available, otherwise fall back to static models
|
||||
const modelInfo = dynamicGroqModels?.[newModelId] || groqModels[newModelId as keyof typeof groqModels]
|
||||
|
||||
handleFieldsChange({
|
||||
groqModelId: newModelId,
|
||||
groqModelInfo: modelInfo,
|
||||
})
|
||||
handleModeFieldsChange(
|
||||
{
|
||||
groqModelId: { plan: "planModeGroqModelId", act: "actModeGroqModelId" },
|
||||
groqModelInfo: { plan: "planModeGroqModelInfo", act: "actModeGroqModelInfo" },
|
||||
},
|
||||
{
|
||||
groqModelId: newModelId,
|
||||
groqModelInfo: modelInfo,
|
||||
},
|
||||
currentMode,
|
||||
)
|
||||
setSearchTerm(newModelId)
|
||||
}
|
||||
|
||||
const { selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
return normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
}, [apiConfiguration, currentMode])
|
||||
|
||||
useMount(() => {
|
||||
ModelsServiceClient.refreshGroqModels(EmptyRequest.create({}))
|
||||
|
||||
@@ -4,21 +4,24 @@ 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 { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
import { ModelsServiceClient } from "../../services/grpc-client"
|
||||
import { highlight } from "../history/HistoryView"
|
||||
import { ModelInfoView } from "./common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "./utils/providerUtils"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "./utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
|
||||
export interface HuggingFaceModelPickerProps {
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
const HuggingFaceModelPicker: React.FC<HuggingFaceModelPickerProps> = ({ isPopup }) => {
|
||||
const HuggingFaceModelPicker: React.FC<HuggingFaceModelPickerProps> = ({ isPopup, currentMode }) => {
|
||||
const { apiConfiguration, huggingFaceModels: dynamicModels, setHuggingFaceModels } = useExtensionState()
|
||||
const { handleFieldsChange } = useApiConfigurationHandlers()
|
||||
const [searchTerm, setSearchTerm] = useState(apiConfiguration?.huggingFaceModelId || huggingFaceDefaultModelId)
|
||||
const { handleModeFieldsChange } = useApiConfigurationHandlers()
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
const [searchTerm, setSearchTerm] = useState(modeFields.huggingFaceModelId || huggingFaceDefaultModelId)
|
||||
const [isDropdownVisible, setIsDropdownVisible] = useState(false)
|
||||
const [selectedIndex, setSelectedIndex] = useState(-1)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
@@ -27,16 +30,25 @@ const HuggingFaceModelPicker: React.FC<HuggingFaceModelPickerProps> = ({ isPopup
|
||||
|
||||
const handleModelChange = (newModelId: string) => {
|
||||
const allModels = { ...huggingFaceModels, ...dynamicModels }
|
||||
handleFieldsChange({
|
||||
huggingFaceModelId: newModelId,
|
||||
huggingFaceModelInfo: allModels[newModelId as keyof typeof allModels],
|
||||
})
|
||||
const modelInfo = allModels[newModelId as keyof typeof allModels]
|
||||
|
||||
handleModeFieldsChange(
|
||||
{
|
||||
huggingFaceModelId: { plan: "planModeHuggingFaceModelId", act: "actModeHuggingFaceModelId" },
|
||||
huggingFaceModelInfo: { plan: "planModeHuggingFaceModelInfo", act: "actModeHuggingFaceModelInfo" },
|
||||
},
|
||||
{
|
||||
huggingFaceModelId: newModelId,
|
||||
huggingFaceModelInfo: modelInfo,
|
||||
},
|
||||
currentMode,
|
||||
)
|
||||
setSearchTerm(newModelId)
|
||||
}
|
||||
|
||||
const { selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
return normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
}, [apiConfiguration, currentMode])
|
||||
|
||||
useMount(() => {
|
||||
ModelsServiceClient.refreshHuggingFaceModels(EmptyRequest.create({}))
|
||||
|
||||
@@ -11,10 +11,11 @@ import { useMount } from "react-use"
|
||||
import styled from "styled-components"
|
||||
import { highlight } from "../history/HistoryView"
|
||||
import { ModelInfoView } from "./common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "./utils/providerUtils"
|
||||
import { getModeSpecificFields, normalizeApiConfiguration } from "./utils/providerUtils"
|
||||
import FeaturedModelCard from "./FeaturedModelCard"
|
||||
import ThinkingBudgetSlider from "./ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
// Star icon for favorites
|
||||
const StarIcon = ({ isFavorite, onClick }: { isFavorite: boolean; onClick: (e: React.MouseEvent) => void }) => {
|
||||
@@ -39,6 +40,7 @@ const StarIcon = ({ isFavorite, onClick }: { isFavorite: boolean; onClick: (e: R
|
||||
|
||||
export interface OpenRouterModelPickerProps {
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
// Featured models for Cline provider
|
||||
@@ -60,10 +62,11 @@ const featuredModels = [
|
||||
},
|
||||
]
|
||||
|
||||
const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }) => {
|
||||
const { handleFieldsChange } = useApiConfigurationHandlers()
|
||||
const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup, currentMode }) => {
|
||||
const { handleModeFieldsChange } = useApiConfigurationHandlers()
|
||||
const { apiConfiguration, openRouterModels, refreshOpenRouterModels } = useExtensionState()
|
||||
const [searchTerm, setSearchTerm] = useState(apiConfiguration?.openRouterModelId || openRouterDefaultModelId)
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
const [searchTerm, setSearchTerm] = useState(modeFields.openRouterModelId || openRouterDefaultModelId)
|
||||
const [isSearchInputDirty, setIsSearchInputDirty] = useState(false)
|
||||
const [isDropdownVisible, setIsDropdownVisible] = useState(false)
|
||||
const [selectedIndex, setSelectedIndex] = useState(-1)
|
||||
@@ -76,25 +79,32 @@ const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }
|
||||
|
||||
setSearchTerm(newModelId)
|
||||
|
||||
handleFieldsChange({
|
||||
openRouterModelId: newModelId,
|
||||
openRouterModelInfo: openRouterModels[newModelId],
|
||||
})
|
||||
handleModeFieldsChange(
|
||||
{
|
||||
openRouterModelId: { plan: "planModeOpenRouterModelId", act: "actModeOpenRouterModelId" },
|
||||
openRouterModelInfo: { plan: "planModeOpenRouterModelInfo", act: "actModeOpenRouterModelInfo" },
|
||||
},
|
||||
{
|
||||
openRouterModelId: newModelId,
|
||||
openRouterModelInfo: openRouterModels[newModelId],
|
||||
},
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
|
||||
const { selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
return normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
}, [apiConfiguration, currentMode])
|
||||
|
||||
useMount(refreshOpenRouterModels)
|
||||
|
||||
// Sync external changes only when user isn't actively typing
|
||||
useEffect(() => {
|
||||
if (!isSearchInputDirty) {
|
||||
const currentModelId = apiConfiguration?.openRouterModelId || openRouterDefaultModelId
|
||||
const currentModelId = modeFields.openRouterModelId || openRouterDefaultModelId
|
||||
setSearchTerm(currentModelId)
|
||||
}
|
||||
}, [apiConfiguration?.openRouterModelId, isSearchInputDirty])
|
||||
}, [modeFields.openRouterModelId, isSearchInputDirty])
|
||||
|
||||
// Reset dirty flag after user stops typing (1 second timeout)
|
||||
useEffect(() => {
|
||||
@@ -121,10 +131,8 @@ const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }
|
||||
const modelIds = useMemo(() => {
|
||||
const unfilteredModelIds = Object.keys(openRouterModels).sort((a, b) => a.localeCompare(b))
|
||||
|
||||
return apiConfiguration?.apiProvider === "cline"
|
||||
? unfilteredModelIds.filter((id) => !id.includes(":free"))
|
||||
: unfilteredModelIds
|
||||
}, [openRouterModels, apiConfiguration?.apiProvider])
|
||||
return modeFields.apiProvider === "cline" ? unfilteredModelIds.filter((id) => !id.includes(":free")) : unfilteredModelIds
|
||||
}, [openRouterModels, modeFields.apiProvider])
|
||||
|
||||
const searchableItems = useMemo(() => {
|
||||
return modelIds.map((id) => ({
|
||||
@@ -237,7 +245,7 @@ const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }
|
||||
<span style={{ fontWeight: 500 }}>Model</span>
|
||||
</label>
|
||||
|
||||
{apiConfiguration?.apiProvider === "cline" && (
|
||||
{modeFields.apiProvider === "cline" && (
|
||||
<div style={{ marginBottom: "6px", marginTop: 4 }}>
|
||||
{featuredModels.map((model) => (
|
||||
<FeaturedModelCard
|
||||
@@ -326,7 +334,7 @@ const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }
|
||||
|
||||
{hasInfo ? (
|
||||
<>
|
||||
{showBudgetSlider && <ThinkingBudgetSlider />}
|
||||
{showBudgetSlider && <ThinkingBudgetSlider currentMode={currentMode} />}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
</>
|
||||
|
||||
@@ -11,18 +11,21 @@ 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 { getModeSpecificFields, normalizeApiConfiguration } from "./utils/providerUtils"
|
||||
import ThinkingBudgetSlider from "./ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "./utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
export interface RequestyModelPickerProps {
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
const RequestyModelPicker: React.FC<RequestyModelPickerProps> = ({ isPopup }) => {
|
||||
const RequestyModelPicker: React.FC<RequestyModelPickerProps> = ({ isPopup, currentMode }) => {
|
||||
const { apiConfiguration, requestyModels, setRequestyModels } = useExtensionState()
|
||||
const { handleFieldsChange } = useApiConfigurationHandlers()
|
||||
const [searchTerm, setSearchTerm] = useState(apiConfiguration?.requestyModelId || requestyDefaultModelId)
|
||||
const { handleModeFieldsChange } = useApiConfigurationHandlers()
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
const [searchTerm, setSearchTerm] = useState(modeFields.requestyModelId || requestyDefaultModelId)
|
||||
const [isDropdownVisible, setIsDropdownVisible] = useState(false)
|
||||
const [selectedIndex, setSelectedIndex] = useState(-1)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
@@ -32,16 +35,23 @@ const RequestyModelPicker: React.FC<RequestyModelPickerProps> = ({ isPopup }) =>
|
||||
const handleModelChange = (newModelId: string) => {
|
||||
// could be setting invalid model id/undefined info but validation will catch it
|
||||
|
||||
handleFieldsChange({
|
||||
requestyModelId: newModelId,
|
||||
requestyModelInfo: requestyModels[newModelId],
|
||||
})
|
||||
handleModeFieldsChange(
|
||||
{
|
||||
requestyModelId: { plan: "planModeRequestyModelId", act: "actModeRequestyModelId" },
|
||||
requestyModelInfo: { plan: "planModeRequestyModelInfo", act: "actModeRequestyModelInfo" },
|
||||
},
|
||||
{
|
||||
requestyModelId: newModelId,
|
||||
requestyModelInfo: requestyModels[newModelId],
|
||||
},
|
||||
currentMode,
|
||||
)
|
||||
setSearchTerm(newModelId)
|
||||
}
|
||||
|
||||
const { selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
return normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
}, [apiConfiguration, currentMode])
|
||||
|
||||
useMount(() => {
|
||||
ModelsServiceClient.refreshRequestyModels(EmptyRequest.create({}))
|
||||
@@ -226,7 +236,7 @@ const RequestyModelPicker: React.FC<RequestyModelPickerProps> = ({ isPopup }) =>
|
||||
|
||||
{hasInfo ? (
|
||||
<>
|
||||
{showBudgetSlider && <ThinkingBudgetSlider />}
|
||||
{showBudgetSlider && <ThinkingBudgetSlider currentMode={currentMode} />}
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -103,7 +103,6 @@ const SettingsView = ({ onDone, targetSection }: SettingsViewProps) => {
|
||||
// Track active tab
|
||||
const [activeTab, setActiveTab] = useState<string>(targetSection || SETTINGS_TABS[0].id)
|
||||
// Track if we're currently switching modes
|
||||
const [isSwitchingMode, setIsSwitchingMode] = useState(false)
|
||||
|
||||
const { version, chatSettings } = useExtensionState()
|
||||
|
||||
@@ -158,34 +157,6 @@ const SettingsView = ({ onDone, targetSection }: SettingsViewProps) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handlePlanActModeChange = async (tab: "plan" | "act") => {
|
||||
// Prevent switching if already in that mode or if currently switching
|
||||
if (tab === chatSettings.mode || isSwitchingMode) {
|
||||
return
|
||||
}
|
||||
|
||||
// All settings save immediately, so we can switch modes directly
|
||||
setIsSwitchingMode(true)
|
||||
|
||||
try {
|
||||
// Perform the mode switch
|
||||
await StateServiceClient.togglePlanActMode(
|
||||
TogglePlanActModeRequest.create({
|
||||
chatSettings: {
|
||||
mode: tab === "plan" ? PlanActMode.PLAN : PlanActMode.ACT,
|
||||
preferredLanguage: chatSettings.preferredLanguage,
|
||||
openAiReasoningEffort: chatSettings.openAIReasoningEffort,
|
||||
},
|
||||
}),
|
||||
)
|
||||
} catch (error) {
|
||||
console.error("Failed to toggle Plan/Act mode:", error)
|
||||
} finally {
|
||||
// Always re-enable mode switching, even on error
|
||||
setIsSwitchingMode(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Update active tab when targetSection changes
|
||||
useEffect(() => {
|
||||
if (targetSection) {
|
||||
@@ -313,13 +284,7 @@ const SettingsView = ({ onDone, targetSection }: SettingsViewProps) => {
|
||||
return (
|
||||
<TabContent className="flex-1 overflow-auto">
|
||||
{/* API Configuration Tab */}
|
||||
{activeTab === "api-config" && (
|
||||
<ApiConfigurationSection
|
||||
isSwitchingMode={isSwitchingMode}
|
||||
handlePlanActModeChange={handlePlanActModeChange}
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "api-config" && <ApiConfigurationSection renderSectionHeader={renderSectionHeader} />}
|
||||
|
||||
{/* General Settings Tab */}
|
||||
{activeTab === "general" && <GeneralSettingsSection renderSectionHeader={renderSectionHeader} />}
|
||||
|
||||
@@ -4,6 +4,8 @@ import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
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"
|
||||
|
||||
// Constants
|
||||
const DEFAULT_MIN_VALID_TOKENS = 1024
|
||||
@@ -83,20 +85,23 @@ const RangeInput = styled.input<{ $value: number; $min: number; $max: number }>`
|
||||
|
||||
interface ThinkingBudgetSliderProps {
|
||||
maxBudget?: number
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
const ThinkingBudgetSlider = ({ maxBudget }: ThinkingBudgetSliderProps) => {
|
||||
const ThinkingBudgetSlider = ({ maxBudget, currentMode }: ThinkingBudgetSliderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const [isEnabled, setIsEnabled] = useState<boolean>((apiConfiguration?.thinkingBudgetTokens || 0) > 0)
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
const [isEnabled, setIsEnabled] = useState<boolean>((modeFields.thinkingBudgetTokens || 0) > 0)
|
||||
|
||||
const maxTokens = useMemo(
|
||||
() =>
|
||||
apiConfiguration?.apiProvider === "gemini"
|
||||
modeFields.apiProvider === "gemini"
|
||||
? geminiModels[geminiDefaultModelId].maxTokens
|
||||
: anthropicModels["claude-3-7-sonnet-20250219"].maxTokens,
|
||||
[apiConfiguration?.apiProvider],
|
||||
[modeFields.apiProvider],
|
||||
)
|
||||
|
||||
// use maxBudget prop if provided, otherwise apply the percentage cap to maxTokens
|
||||
@@ -108,7 +113,7 @@ const ThinkingBudgetSlider = ({ maxBudget }: ThinkingBudgetSliderProps) => {
|
||||
}, [maxBudget, maxTokens])
|
||||
|
||||
// Add local state for the slider value
|
||||
const [localValue, setLocalValue] = useState(apiConfiguration?.thinkingBudgetTokens || 0)
|
||||
const [localValue, setLocalValue] = useState(modeFields.thinkingBudgetTokens || 0)
|
||||
|
||||
const handleSliderChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = parseInt(event.target.value, 10)
|
||||
@@ -116,7 +121,11 @@ const ThinkingBudgetSlider = ({ maxBudget }: ThinkingBudgetSliderProps) => {
|
||||
}, [])
|
||||
|
||||
const handleSliderComplete = () => {
|
||||
handleFieldChange("thinkingBudgetTokens", localValue)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeThinkingBudgetTokens", act: "actModeThinkingBudgetTokens" },
|
||||
localValue,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
|
||||
const handleToggleChange = (event: any) => {
|
||||
@@ -125,7 +134,7 @@ const ThinkingBudgetSlider = ({ maxBudget }: ThinkingBudgetSliderProps) => {
|
||||
setIsEnabled(isChecked)
|
||||
setLocalValue(newValue)
|
||||
|
||||
handleFieldChange("thinkingBudgetTokens", newValue)
|
||||
handleModeFieldChange({ plan: "planModeThinkingBudgetTokens", act: "actModeThinkingBudgetTokens" }, newValue, currentMode)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,13 +11,16 @@ vi.mock("../../../context/ExtensionStateContext", async (importOriginal) => {
|
||||
// your mocked methods
|
||||
useExtensionState: vi.fn(() => ({
|
||||
apiConfiguration: {
|
||||
apiProvider: "requesty",
|
||||
planModeApiProvider: "requesty",
|
||||
actModeApiProvider: "requesty",
|
||||
requestyApiKey: "",
|
||||
requestyModelId: "",
|
||||
planModeRequestyModelId: "",
|
||||
actModeRequestyModelId: "",
|
||||
},
|
||||
setApiConfiguration: vi.fn(),
|
||||
uriScheme: "vscode",
|
||||
requestyModels: {},
|
||||
planActSeparateModelsSetting: false,
|
||||
})),
|
||||
}
|
||||
})
|
||||
@@ -28,6 +31,7 @@ const mockExtensionState = (apiConfiguration: Partial<ApiConfiguration>) => {
|
||||
setApiConfiguration: vi.fn(),
|
||||
uriScheme: "vscode",
|
||||
requestyModels: {},
|
||||
planActSeparateModelsSetting: false,
|
||||
} as any)
|
||||
}
|
||||
|
||||
@@ -39,14 +43,15 @@ describe("ApiOptions Component", () => {
|
||||
//@ts-expect-error - vscode is not defined in the global namespace in test environment
|
||||
global.vscode = { postMessage: mockPostMessage }
|
||||
mockExtensionState({
|
||||
apiProvider: "requesty",
|
||||
planModeApiProvider: "requesty",
|
||||
actModeApiProvider: "requesty",
|
||||
})
|
||||
})
|
||||
|
||||
it("renders Requesty API Key input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const apiKeyInput = screen.getByPlaceholderText("Enter API Key...")
|
||||
@@ -56,7 +61,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Requesty Model ID input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const modelIdInput = screen.getByPlaceholderText("Search and select a model...")
|
||||
@@ -72,14 +77,15 @@ describe("ApiOptions Component", () => {
|
||||
//@ts-expect-error - vscode is not defined in the global namespace in test environment
|
||||
global.vscode = { postMessage: mockPostMessage }
|
||||
mockExtensionState({
|
||||
apiProvider: "together",
|
||||
planModeApiProvider: "together",
|
||||
actModeApiProvider: "together",
|
||||
})
|
||||
})
|
||||
|
||||
it("renders Together API Key input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const apiKeyInput = screen.getByPlaceholderText("Enter API Key...")
|
||||
@@ -89,7 +95,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Together Model ID input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const modelIdInput = screen.getByPlaceholderText("Enter Model ID...")
|
||||
@@ -106,9 +112,11 @@ describe("ApiOptions Component", () => {
|
||||
global.vscode = { postMessage: mockPostMessage }
|
||||
|
||||
mockExtensionState({
|
||||
apiProvider: "fireworks",
|
||||
planModeApiProvider: "fireworks",
|
||||
actModeApiProvider: "fireworks",
|
||||
fireworksApiKey: "",
|
||||
fireworksModelId: "",
|
||||
planModeFireworksModelId: "",
|
||||
actModeFireworksModelId: "",
|
||||
fireworksModelMaxCompletionTokens: 2000,
|
||||
fireworksModelMaxTokens: 4000,
|
||||
})
|
||||
@@ -117,7 +125,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Fireworks API Key input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const apiKeyInput = screen.getByPlaceholderText("Enter API Key...")
|
||||
@@ -127,7 +135,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Fireworks Model ID input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const modelIdInput = screen.getByPlaceholderText("Enter Model ID...")
|
||||
@@ -137,7 +145,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Fireworks Max Completion Tokens input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const maxCompletionTokensInput = screen.getByPlaceholderText("2000")
|
||||
@@ -147,7 +155,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Fireworks Max Tokens input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const maxTokensInput = screen.getByPlaceholderText("4000")
|
||||
@@ -163,14 +171,15 @@ describe("OpenApiInfoOptions", () => {
|
||||
//@ts-expect-error - vscode is not defined in the global namespace in test environment
|
||||
global.vscode = { postMessage: mockPostMessage }
|
||||
mockExtensionState({
|
||||
apiProvider: "openai",
|
||||
planModeApiProvider: "openai",
|
||||
actModeApiProvider: "openai",
|
||||
})
|
||||
})
|
||||
|
||||
it("renders OpenAI Supports Images input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
fireEvent.click(screen.getByText("Model Configuration"))
|
||||
@@ -181,7 +190,7 @@ describe("OpenApiInfoOptions", () => {
|
||||
it("renders OpenAI Context Window Size input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
fireEvent.click(screen.getByText("Model Configuration"))
|
||||
@@ -192,7 +201,7 @@ describe("OpenApiInfoOptions", () => {
|
||||
it("renders OpenAI Max Output Tokens input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
fireEvent.click(screen.getByText("Model Configuration"))
|
||||
@@ -210,7 +219,8 @@ describe("ApiOptions Component", () => {
|
||||
global.vscode = { postMessage: mockPostMessage }
|
||||
|
||||
mockExtensionState({
|
||||
apiProvider: "nebius",
|
||||
planModeApiProvider: "nebius",
|
||||
actModeApiProvider: "nebius",
|
||||
nebiusApiKey: "",
|
||||
})
|
||||
})
|
||||
@@ -218,7 +228,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Nebius API Key input", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const apiKeyInput = screen.getByPlaceholderText("Enter API Key...")
|
||||
@@ -228,7 +238,7 @@ describe("ApiOptions Component", () => {
|
||||
it("renders Nebius Model ID select with a default model", () => {
|
||||
render(
|
||||
<ExtensionStateContextProvider>
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode="plan" />
|
||||
</ExtensionStateContextProvider>,
|
||||
)
|
||||
const modelIdSelect = screen.getByLabelText("Model")
|
||||
|
||||
@@ -3,10 +3,11 @@ import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { BaseUrlField } from "../common/BaseUrlField"
|
||||
import { ModelSelector } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { getModeSpecificFields, normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
// Anthropic models that support thinking/reasoning mode
|
||||
export const SUPPORTED_ANTHROPIC_THINKING_MODELS = [
|
||||
@@ -21,17 +22,18 @@ export const SUPPORTED_ANTHROPIC_THINKING_MODELS = [
|
||||
interface AnthropicProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Anthropic provider configuration component
|
||||
*/
|
||||
export const AnthropicProvider = ({ showModelOptions, isPopup }: AnthropicProviderProps) => {
|
||||
export const AnthropicProvider = ({ showModelOptions, isPopup, currentMode }: AnthropicProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -54,12 +56,18 @@ export const AnthropicProvider = ({ showModelOptions, isPopup }: AnthropicProvid
|
||||
<ModelSelector
|
||||
models={anthropicModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
{SUPPORTED_ANTHROPIC_THINKING_MODELS.includes(selectedModelId) && (
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} />
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
|
||||
@@ -6,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the AskSageProvider component
|
||||
@@ -13,17 +14,18 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface AskSageProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The AskSage provider configuration component
|
||||
*/
|
||||
export const AskSageProvider = ({ showModelOptions, isPopup }: AskSageProviderProps) => {
|
||||
export const AskSageProvider = ({ showModelOptions, isPopup, currentMode }: AskSageProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -48,7 +50,13 @@ export const AskSageProvider = ({ showModelOptions, isPopup }: AskSageProviderPr
|
||||
<ModelSelector
|
||||
models={askSageModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { DropdownContainer } from "../common/ModelSelector"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
// Z-index constants for proper dropdown layering
|
||||
const DROPDOWN_Z_INDEX = 1000
|
||||
@@ -15,13 +16,15 @@ const DROPDOWN_Z_INDEX = 1000
|
||||
interface BedrockProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
export const BedrockProvider = ({ showModelOptions, isPopup }: BedrockProviderProps) => {
|
||||
export const BedrockProvider = ({ showModelOptions, isPopup, currentMode }: BedrockProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange, handleFieldsChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleFieldsChange, handleModeFieldChange, handleModeFieldsChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
const [awsEndpointSelected, setAwsEndpointSelected] = useState(!!apiConfiguration?.awsBedrockEndpoint)
|
||||
|
||||
return (
|
||||
@@ -207,15 +210,29 @@ export const BedrockProvider = ({ showModelOptions, isPopup }: BedrockProviderPr
|
||||
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 2} className="dropdown-container">
|
||||
<VSCodeDropdown
|
||||
id="bedrock-model-dropdown"
|
||||
value={apiConfiguration?.awsBedrockCustomSelected ? "custom" : selectedModelId}
|
||||
value={modeFields.awsBedrockCustomSelected ? "custom" : selectedModelId}
|
||||
onChange={(e: any) => {
|
||||
const isCustom = e.target.value === "custom"
|
||||
|
||||
handleFieldsChange({
|
||||
apiModelId: isCustom ? "" : e.target.value,
|
||||
awsBedrockCustomSelected: isCustom,
|
||||
awsBedrockCustomModelBaseId: bedrockDefaultModelId,
|
||||
})
|
||||
handleModeFieldsChange(
|
||||
{
|
||||
apiModelId: { plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
awsBedrockCustomSelected: {
|
||||
plan: "planModeAwsBedrockCustomSelected",
|
||||
act: "actModeAwsBedrockCustomSelected",
|
||||
},
|
||||
awsBedrockCustomModelBaseId: {
|
||||
plan: "planModeAwsBedrockCustomModelBaseId",
|
||||
act: "actModeAwsBedrockCustomModelBaseId",
|
||||
},
|
||||
},
|
||||
{
|
||||
apiModelId: isCustom ? "" : e.target.value,
|
||||
awsBedrockCustomSelected: isCustom,
|
||||
awsBedrockCustomModelBaseId: bedrockDefaultModelId,
|
||||
},
|
||||
currentMode,
|
||||
)
|
||||
}}
|
||||
style={{ width: "100%" }}>
|
||||
<VSCodeOption value="">Select a model...</VSCodeOption>
|
||||
@@ -235,7 +252,7 @@ export const BedrockProvider = ({ showModelOptions, isPopup }: BedrockProviderPr
|
||||
</VSCodeDropdown>
|
||||
</DropdownContainer>
|
||||
|
||||
{apiConfiguration?.awsBedrockCustomSelected && (
|
||||
{modeFields.awsBedrockCustomSelected && (
|
||||
<div>
|
||||
<p
|
||||
style={{
|
||||
@@ -248,8 +265,14 @@ export const BedrockProvider = ({ showModelOptions, isPopup }: BedrockProviderPr
|
||||
</p>
|
||||
<DebouncedTextField
|
||||
id="bedrock-model-input"
|
||||
initialValue={apiConfiguration?.apiModelId || ""}
|
||||
onChange={(value) => handleFieldChange("apiModelId", value)}
|
||||
initialValue={modeFields.apiModelId || ""}
|
||||
onChange={(value) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
style={{ width: "100%", marginTop: 3 }}
|
||||
placeholder="Enter custom model ID...">
|
||||
<span style={{ fontWeight: 500 }}>Model ID</span>
|
||||
@@ -260,8 +283,17 @@ export const BedrockProvider = ({ showModelOptions, isPopup }: BedrockProviderPr
|
||||
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 3} className="dropdown-container">
|
||||
<VSCodeDropdown
|
||||
id="bedrock-base-model-dropdown"
|
||||
value={apiConfiguration?.awsBedrockCustomModelBaseId || bedrockDefaultModelId}
|
||||
onChange={(e: any) => handleFieldChange("awsBedrockCustomModelBaseId", e.target.value)}
|
||||
value={modeFields.awsBedrockCustomModelBaseId || bedrockDefaultModelId}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{
|
||||
plan: "planModeAwsBedrockCustomModelBaseId",
|
||||
act: "actModeAwsBedrockCustomModelBaseId",
|
||||
},
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
style={{ width: "100%" }}>
|
||||
<VSCodeOption value="">Select a model...</VSCodeOption>
|
||||
{Object.keys(bedrockModels).map((modelId) => (
|
||||
@@ -284,13 +316,13 @@ export const BedrockProvider = ({ showModelOptions, isPopup }: BedrockProviderPr
|
||||
{(selectedModelId === "anthropic.claude-3-7-sonnet-20250219-v1:0" ||
|
||||
selectedModelId === "anthropic.claude-sonnet-4-20250514-v1:0" ||
|
||||
selectedModelId === "anthropic.claude-opus-4-20250514-v1:0" ||
|
||||
(apiConfiguration?.awsBedrockCustomSelected &&
|
||||
apiConfiguration?.awsBedrockCustomModelBaseId === "anthropic.claude-3-7-sonnet-20250219-v1:0") ||
|
||||
(apiConfiguration?.awsBedrockCustomSelected &&
|
||||
apiConfiguration?.awsBedrockCustomModelBaseId === "anthropic.claude-sonnet-4-20250514-v1:0") ||
|
||||
(apiConfiguration?.awsBedrockCustomSelected &&
|
||||
apiConfiguration?.awsBedrockCustomModelBaseId === "anthropic.claude-opus-4-20250514-v1:0")) && (
|
||||
<ThinkingBudgetSlider />
|
||||
(modeFields.awsBedrockCustomSelected &&
|
||||
modeFields.awsBedrockCustomModelBaseId === "anthropic.claude-3-7-sonnet-20250219-v1:0") ||
|
||||
(modeFields.awsBedrockCustomSelected &&
|
||||
modeFields.awsBedrockCustomModelBaseId === "anthropic.claude-sonnet-4-20250514-v1:0") ||
|
||||
(modeFields.awsBedrockCustomSelected &&
|
||||
modeFields.awsBedrockCustomModelBaseId === "anthropic.claude-opus-4-20250514-v1:0")) && (
|
||||
<ThinkingBudgetSlider currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the CerebrasProvider component
|
||||
@@ -12,17 +13,18 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface CerebrasProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Cerebras provider configuration component
|
||||
*/
|
||||
export const CerebrasProvider = ({ showModelOptions, isPopup }: CerebrasProviderProps) => {
|
||||
export const CerebrasProvider = ({ showModelOptions, isPopup, currentMode }: CerebrasProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +40,13 @@ export const CerebrasProvider = ({ showModelOptions, isPopup }: CerebrasProvider
|
||||
<ModelSelector
|
||||
models={cerebrasModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -7,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the ClaudeCodeProvider component
|
||||
@@ -14,17 +15,18 @@ import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
interface ClaudeCodeProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Claude Code provider configuration component
|
||||
*/
|
||||
export const ClaudeCodeProvider = ({ showModelOptions, isPopup }: ClaudeCodeProviderProps) => {
|
||||
export const ClaudeCodeProvider = ({ showModelOptions, isPopup, currentMode }: ClaudeCodeProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -51,12 +53,18 @@ export const ClaudeCodeProvider = ({ showModelOptions, isPopup }: ClaudeCodeProv
|
||||
<ModelSelector
|
||||
models={claudeCodeModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
{SUPPORTED_ANTHROPIC_THINKING_MODELS.includes(selectedModelId) && (
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} />
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
|
||||
@@ -6,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the ClineProvider component
|
||||
@@ -13,12 +14,13 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface ClineProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Cline provider configuration component
|
||||
*/
|
||||
export const ClineProvider = ({ showModelOptions, isPopup }: ClineProviderProps) => {
|
||||
export const ClineProvider = ({ showModelOptions, isPopup, currentMode }: ClineProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
@@ -76,7 +78,7 @@ export const ClineProvider = ({ showModelOptions, isPopup }: ClineProviderProps)
|
||||
)}
|
||||
|
||||
{/* OpenRouter Model Picker */}
|
||||
<OpenRouterModelPicker isPopup={isPopup} />
|
||||
<OpenRouterModelPicker isPopup={isPopup} currentMode={currentMode} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the DeepSeekProvider component
|
||||
@@ -12,17 +13,18 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface DeepSeekProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The DeepSeek provider configuration component
|
||||
*/
|
||||
export const DeepSeekProvider = ({ showModelOptions, isPopup }: DeepSeekProviderProps) => {
|
||||
export const DeepSeekProvider = ({ showModelOptions, isPopup, currentMode }: DeepSeekProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +40,13 @@ export const DeepSeekProvider = ({ showModelOptions, isPopup }: DeepSeekProvider
|
||||
<ModelSelector
|
||||
models={deepSeekModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the DoubaoProvider component
|
||||
@@ -12,17 +13,18 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface DoubaoProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The ByteDance Doubao provider configuration component
|
||||
*/
|
||||
export const DoubaoProvider = ({ showModelOptions, isPopup }: DoubaoProviderProps) => {
|
||||
export const DoubaoProvider = ({ showModelOptions, isPopup, currentMode }: DoubaoProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +40,13 @@ export const DoubaoProvider = ({ showModelOptions, isPopup }: DoubaoProviderProp
|
||||
<ModelSelector
|
||||
models={doubaoModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
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"
|
||||
|
||||
/**
|
||||
* Props for the FireworksProvider component
|
||||
@@ -10,14 +12,17 @@ import { ApiConfiguration } from "@shared/api"
|
||||
interface FireworksProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Fireworks provider configuration component
|
||||
*/
|
||||
export const FireworksProvider = ({ showModelOptions, isPopup }: FireworksProviderProps) => {
|
||||
export const FireworksProvider = ({ showModelOptions, isPopup, currentMode }: FireworksProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleModeFieldChange, handleFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { fireworksModelId } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
// Handler for number input fields with validation
|
||||
const handleNumberInputChange = (field: keyof ApiConfiguration, value: string) => {
|
||||
@@ -43,8 +48,14 @@ export const FireworksProvider = ({ showModelOptions, isPopup }: FireworksProvid
|
||||
{showModelOptions && (
|
||||
<>
|
||||
<DebouncedTextField
|
||||
initialValue={apiConfiguration?.fireworksModelId || ""}
|
||||
onChange={(value) => handleFieldChange("fireworksModelId", value)}
|
||||
initialValue={fireworksModelId || ""}
|
||||
onChange={(value) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeFireworksModelId", act: "actModeFireworksModelId" },
|
||||
value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
style={{ width: "100%" }}
|
||||
placeholder={"Enter Model ID..."}>
|
||||
<span style={{ fontWeight: 500 }}>Model ID</span>
|
||||
|
||||
@@ -7,6 +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"
|
||||
|
||||
// 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"]
|
||||
@@ -17,17 +18,18 @@ const SUPPORTED_THINKING_MODELS = ["gemini-2.5-pro", "gemini-2.5-flash", "gemini
|
||||
interface GeminiProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Gemini provider configuration component
|
||||
*/
|
||||
export const GeminiProvider = ({ showModelOptions, isPopup }: GeminiProviderProps) => {
|
||||
export const GeminiProvider = ({ showModelOptions, isPopup, currentMode }: GeminiProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -50,12 +52,18 @@ export const GeminiProvider = ({ showModelOptions, isPopup }: GeminiProviderProp
|
||||
<ModelSelector
|
||||
models={geminiModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
{SUPPORTED_THINKING_MODELS.includes(selectedModelId) && (
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} />
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import GroqModelPicker from "../GroqModelPicker"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
@@ -9,12 +10,13 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface GroqProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Groq provider configuration component
|
||||
*/
|
||||
export const GroqProvider = ({ showModelOptions, isPopup }: GroqProviderProps) => {
|
||||
export const GroqProvider = ({ showModelOptions, isPopup, currentMode }: GroqProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
@@ -27,7 +29,7 @@ export const GroqProvider = ({ showModelOptions, isPopup }: GroqProviderProps) =
|
||||
signupUrl="https://console.groq.com/keys"
|
||||
/>
|
||||
|
||||
{showModelOptions && <GroqModelPicker isPopup={isPopup} />}
|
||||
{showModelOptions && <GroqModelPicker isPopup={isPopup} currentMode={currentMode} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { huggingFaceModels } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { ModelSelector } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
@@ -13,17 +14,18 @@ import { HuggingFaceModelPicker } from "../HuggingFaceModelPicker"
|
||||
interface HuggingFaceProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Hugging Face provider configuration component
|
||||
*/
|
||||
export const HuggingFaceProvider = ({ showModelOptions, isPopup }: HuggingFaceProviderProps) => {
|
||||
export const HuggingFaceProvider = ({ showModelOptions, isPopup, currentMode }: HuggingFaceProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -50,7 +52,7 @@ export const HuggingFaceProvider = ({ showModelOptions, isPopup }: HuggingFacePr
|
||||
|
||||
{showModelOptions && (
|
||||
<>
|
||||
<HuggingFaceModelPicker isPopup={isPopup} />
|
||||
<HuggingFaceModelPicker isPopup={isPopup} currentMode={currentMode} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,8 @@ import { StringRequest } from "@shared/proto/common"
|
||||
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"
|
||||
|
||||
/**
|
||||
* Props for the LMStudioProvider component
|
||||
@@ -14,14 +16,17 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface LMStudioProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The LM Studio provider configuration component
|
||||
*/
|
||||
export const LMStudioProvider = ({ showModelOptions, isPopup }: LMStudioProviderProps) => {
|
||||
export const LMStudioProvider = ({ showModelOptions, isPopup, currentMode }: LMStudioProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { lmStudioModelId } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
const [lmStudioModels, setLmStudioModels] = useState<string[]>([])
|
||||
|
||||
@@ -58,8 +63,10 @@ export const LMStudioProvider = ({ showModelOptions, isPopup }: LMStudioProvider
|
||||
/>
|
||||
|
||||
<DebouncedTextField
|
||||
initialValue={apiConfiguration?.lmStudioModelId || ""}
|
||||
onChange={(value) => handleFieldChange("lmStudioModelId", value)}
|
||||
initialValue={lmStudioModelId || ""}
|
||||
onChange={(value) =>
|
||||
handleModeFieldChange({ plan: "planModeLmStudioModelId", act: "actModeLmStudioModelId" }, value, currentMode)
|
||||
}
|
||||
style={{ width: "100%" }}
|
||||
placeholder={"e.g. meta-llama-3.1-8b-instruct"}>
|
||||
<span style={{ fontWeight: 500 }}>Model ID</span>
|
||||
@@ -67,18 +74,20 @@ export const LMStudioProvider = ({ showModelOptions, isPopup }: LMStudioProvider
|
||||
|
||||
{lmStudioModels.length > 0 && (
|
||||
<VSCodeRadioGroup
|
||||
value={
|
||||
lmStudioModels.includes(apiConfiguration?.lmStudioModelId || "") ? apiConfiguration?.lmStudioModelId : ""
|
||||
}
|
||||
value={lmStudioModels.includes(lmStudioModelId || "") ? lmStudioModelId : ""}
|
||||
onChange={(e) => {
|
||||
const value = (e.target as HTMLInputElement)?.value
|
||||
// need to check value first since radio group returns empty string sometimes
|
||||
if (value) {
|
||||
handleFieldChange("lmStudioModelId", value)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeLmStudioModelId", act: "actModeLmStudioModelId" },
|
||||
value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
}}>
|
||||
{lmStudioModels.map((model) => (
|
||||
<VSCodeRadio key={model} value={model} checked={apiConfiguration?.lmStudioModelId === model}>
|
||||
<VSCodeRadio key={model} value={model} checked={lmStudioModelId === model}>
|
||||
{model}
|
||||
</VSCodeRadio>
|
||||
))}
|
||||
|
||||
@@ -3,11 +3,12 @@ import { liteLlmModelInfoSaneDefaults } from "@shared/api"
|
||||
import { VSCodeCheckbox, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { getAsVar, VSC_DESCRIPTION_FOREGROUND } from "@/utils/vscStyles"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
/**
|
||||
* Props for the LiteLlmProvider component
|
||||
@@ -15,17 +16,21 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface LiteLlmProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The LiteLLM provider configuration component
|
||||
*/
|
||||
export const LiteLlmProvider = ({ showModelOptions, isPopup }: LiteLlmProviderProps) => {
|
||||
export const LiteLlmProvider = ({ showModelOptions, isPopup, currentMode }: LiteLlmProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
// Get mode-specific fields
|
||||
const { liteLlmModelId, liteLlmModelInfo } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
// Local state for collapsible model configuration section
|
||||
const [modelConfigurationSelected, setModelConfigurationSelected] = useState(false)
|
||||
@@ -49,8 +54,10 @@ export const LiteLlmProvider = ({ showModelOptions, isPopup }: LiteLlmProviderPr
|
||||
<span style={{ fontWeight: 500 }}>API Key</span>
|
||||
</DebouncedTextField>
|
||||
<DebouncedTextField
|
||||
initialValue={apiConfiguration?.liteLlmModelId || ""}
|
||||
onChange={(value) => handleFieldChange("liteLlmModelId", value)}
|
||||
initialValue={liteLlmModelId || ""}
|
||||
onChange={(value) =>
|
||||
handleModeFieldChange({ plan: "planModeLiteLlmModelId", act: "actModeLiteLlmModelId" }, value, currentMode)
|
||||
}
|
||||
style={{ width: "100%" }}
|
||||
placeholder={"e.g. anthropic/claude-sonnet-4-20250514"}>
|
||||
<span style={{ fontWeight: 500 }}>Model ID</span>
|
||||
@@ -77,7 +84,7 @@ export const LiteLlmProvider = ({ showModelOptions, isPopup }: LiteLlmProviderPr
|
||||
</div>
|
||||
|
||||
<>
|
||||
<ThinkingBudgetSlider />
|
||||
<ThinkingBudgetSlider currentMode={currentMode} />
|
||||
<p
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
@@ -118,50 +125,56 @@ export const LiteLlmProvider = ({ showModelOptions, isPopup }: LiteLlmProviderPr
|
||||
{modelConfigurationSelected && (
|
||||
<>
|
||||
<VSCodeCheckbox
|
||||
checked={!!apiConfiguration?.liteLlmModelInfo?.supportsImages}
|
||||
checked={!!liteLlmModelInfo?.supportsImages}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
const modelInfo = apiConfiguration?.liteLlmModelInfo
|
||||
? apiConfiguration.liteLlmModelInfo
|
||||
: { ...liteLlmModelInfoSaneDefaults }
|
||||
const modelInfo = liteLlmModelInfo ? liteLlmModelInfo : { ...liteLlmModelInfoSaneDefaults }
|
||||
modelInfo.supportsImages = isChecked
|
||||
|
||||
handleFieldChange("liteLlmModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeLiteLlmModelInfo", act: "actModeLiteLlmModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
Supports Images
|
||||
</VSCodeCheckbox>
|
||||
<div style={{ display: "flex", gap: 10, marginTop: "5px" }}>
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.liteLlmModelInfo?.contextWindow
|
||||
? apiConfiguration.liteLlmModelInfo.contextWindow.toString()
|
||||
liteLlmModelInfo?.contextWindow
|
||||
? liteLlmModelInfo.contextWindow.toString()
|
||||
: (liteLlmModelInfoSaneDefaults.contextWindow?.toString() ?? "")
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.liteLlmModelInfo
|
||||
? apiConfiguration.liteLlmModelInfo
|
||||
: { ...liteLlmModelInfoSaneDefaults }
|
||||
const modelInfo = liteLlmModelInfo ? liteLlmModelInfo : { ...liteLlmModelInfoSaneDefaults }
|
||||
modelInfo.contextWindow = Number(value)
|
||||
|
||||
handleFieldChange("liteLlmModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeLiteLlmModelInfo", act: "actModeLiteLlmModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Context Window Size</span>
|
||||
</DebouncedTextField>
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.liteLlmModelInfo?.maxTokens
|
||||
? apiConfiguration.liteLlmModelInfo.maxTokens.toString()
|
||||
liteLlmModelInfo?.maxTokens
|
||||
? liteLlmModelInfo.maxTokens.toString()
|
||||
: (liteLlmModelInfoSaneDefaults.maxTokens?.toString() ?? "")
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.liteLlmModelInfo
|
||||
? apiConfiguration.liteLlmModelInfo
|
||||
: { ...liteLlmModelInfoSaneDefaults }
|
||||
const modelInfo = liteLlmModelInfo ? liteLlmModelInfo : { ...liteLlmModelInfoSaneDefaults }
|
||||
modelInfo.maxTokens = Number(value)
|
||||
|
||||
handleFieldChange("liteLlmModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeLiteLlmModelInfo", act: "actModeLiteLlmModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Max Output Tokens</span>
|
||||
</DebouncedTextField>
|
||||
@@ -169,14 +182,12 @@ export const LiteLlmProvider = ({ showModelOptions, isPopup }: LiteLlmProviderPr
|
||||
<div style={{ display: "flex", gap: 10, marginTop: "5px" }}>
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.liteLlmModelInfo?.temperature !== undefined
|
||||
? apiConfiguration.liteLlmModelInfo.temperature.toString()
|
||||
liteLlmModelInfo?.temperature !== undefined
|
||||
? liteLlmModelInfo.temperature.toString()
|
||||
: (liteLlmModelInfoSaneDefaults.temperature?.toString() ?? "")
|
||||
}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.liteLlmModelInfo
|
||||
? apiConfiguration.liteLlmModelInfo
|
||||
: { ...liteLlmModelInfoSaneDefaults }
|
||||
const modelInfo = liteLlmModelInfo ? liteLlmModelInfo : { ...liteLlmModelInfoSaneDefaults }
|
||||
|
||||
// Check if the input ends with a decimal point or has trailing zeros after decimal
|
||||
const shouldPreserveFormat = value.endsWith(".") || (value.includes(".") && value.endsWith("0"))
|
||||
@@ -184,7 +195,11 @@ export const LiteLlmProvider = ({ showModelOptions, isPopup }: LiteLlmProviderPr
|
||||
modelInfo.temperature =
|
||||
value === "" ? liteLlmModelInfoSaneDefaults.temperature : parseFloat(value)
|
||||
|
||||
handleFieldChange("liteLlmModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeLiteLlmModelInfo", act: "actModeLiteLlmModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Temperature</span>
|
||||
</DebouncedTextField>
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the MistralProvider component
|
||||
@@ -12,17 +13,18 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface MistralProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Mistral provider configuration component
|
||||
*/
|
||||
export const MistralProvider = ({ showModelOptions, isPopup }: MistralProviderProps) => {
|
||||
export const MistralProvider = ({ showModelOptions, isPopup, currentMode }: MistralProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +40,13 @@ export const MistralProvider = ({ showModelOptions, isPopup }: MistralProviderPr
|
||||
<ModelSelector
|
||||
models={mistralModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useState } from "react"
|
||||
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
/**
|
||||
* Props for the MoonshotProvider component
|
||||
@@ -14,20 +15,21 @@ import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
interface MoonshotProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Moonshot AI Studio provider configuration component
|
||||
*/
|
||||
export const MoonshotProvider = ({ showModelOptions, isPopup }: MoonshotProviderProps) => {
|
||||
export const MoonshotProvider = ({ showModelOptions, isPopup, currentMode }: MoonshotProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Local state for Chinese API endpoint checkbox
|
||||
const [isChineseEndpoint, setIsChineseEndpoint] = useState(!!apiConfiguration?.moonshotApiLine)
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
const handleChineseEndpointToggle = (e: any) => {
|
||||
const checked = e.target.checked === true
|
||||
@@ -57,7 +59,13 @@ export const MoonshotProvider = ({ showModelOptions, isPopup }: MoonshotProvider
|
||||
<ModelSelector
|
||||
models={moonshotModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the NebiusProvider component
|
||||
@@ -12,17 +13,17 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface NebiusProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Nebius AI Studio provider configuration component
|
||||
*/
|
||||
export const NebiusProvider = ({ showModelOptions, isPopup }: NebiusProviderProps) => {
|
||||
export const NebiusProvider = ({ showModelOptions, isPopup, currentMode }: NebiusProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -39,7 +40,13 @@ export const NebiusProvider = ({ showModelOptions, isPopup }: NebiusProviderProp
|
||||
<ModelSelector
|
||||
models={nebiusModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import OllamaModelPicker from "../OllamaModelPicker"
|
||||
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"
|
||||
|
||||
/**
|
||||
* Props for the OllamaProvider component
|
||||
@@ -15,14 +17,17 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface OllamaProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Ollama provider configuration component
|
||||
*/
|
||||
export const OllamaProvider = ({ showModelOptions, isPopup }: OllamaProviderProps) => {
|
||||
export const OllamaProvider = ({ showModelOptions, isPopup, currentMode }: OllamaProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { ollamaModelId } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
const [ollamaModels, setOllamaModels] = useState<string[]>([])
|
||||
|
||||
@@ -64,9 +69,9 @@ export const OllamaProvider = ({ showModelOptions, isPopup }: OllamaProviderProp
|
||||
</label>
|
||||
<OllamaModelPicker
|
||||
ollamaModels={ollamaModels}
|
||||
selectedModelId={apiConfiguration?.ollamaModelId || ""}
|
||||
selectedModelId={ollamaModelId || ""}
|
||||
onModelChange={(modelId) => {
|
||||
handleFieldChange("ollamaModelId", modelId)
|
||||
handleModeFieldChange({ plan: "planModeOllamaModelId", act: "actModeOllamaModelId" }, modelId, currentMode)
|
||||
}}
|
||||
placeholder={ollamaModels.length > 0 ? "Search and select a model..." : "e.g. llama3.1"}
|
||||
/>
|
||||
|
||||
@@ -8,9 +8,10 @@ import { DebouncedTextField } from "../common/DebouncedTextField"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { BaseUrlField } from "../common/BaseUrlField"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { normalizeApiConfiguration, getModeSpecificFields } from "../utils/providerUtils"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
/**
|
||||
* Props for the OpenAICompatibleProvider component
|
||||
@@ -18,19 +19,23 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface OpenAICompatibleProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The OpenAI Compatible provider configuration component
|
||||
*/
|
||||
export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICompatibleProviderProps) => {
|
||||
export const OpenAICompatibleProvider = ({ showModelOptions, isPopup, currentMode }: OpenAICompatibleProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const [modelConfigurationSelected, setModelConfigurationSelected] = useState(false)
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
// Get mode-specific fields
|
||||
const { openAiModelInfo } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
// Debounced function to refresh OpenAI models (prevents excessive API calls while typing)
|
||||
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null)
|
||||
@@ -86,8 +91,10 @@ export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICo
|
||||
/>
|
||||
|
||||
<DebouncedTextField
|
||||
initialValue={apiConfiguration?.openAiModelId || ""}
|
||||
onChange={(value) => handleFieldChange("openAiModelId", value)}
|
||||
initialValue={selectedModelId || ""}
|
||||
onChange={(value) =>
|
||||
handleModeFieldChange({ plan: "planModeOpenAiModelId", act: "actModeOpenAiModelId" }, value, currentMode)
|
||||
}
|
||||
style={{ width: "100%", marginBottom: 10 }}
|
||||
placeholder={"Enter Model ID..."}>
|
||||
<span style={{ fontWeight: 500 }}>Model ID</span>
|
||||
@@ -188,41 +195,47 @@ export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICo
|
||||
{modelConfigurationSelected && (
|
||||
<>
|
||||
<VSCodeCheckbox
|
||||
checked={!!apiConfiguration?.openAiModelInfo?.supportsImages}
|
||||
checked={!!openAiModelInfo?.supportsImages}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
const modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
const modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo.supportsImages = isChecked
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
Supports Images
|
||||
</VSCodeCheckbox>
|
||||
|
||||
<VSCodeCheckbox
|
||||
checked={!!apiConfiguration?.openAiModelInfo?.supportsImages}
|
||||
checked={!!openAiModelInfo?.supportsImages}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
let modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
let modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo.supportsImages = isChecked
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
Supports browser use
|
||||
</VSCodeCheckbox>
|
||||
|
||||
<VSCodeCheckbox
|
||||
checked={!!apiConfiguration?.openAiModelInfo?.isR1FormatRequired}
|
||||
checked={!!openAiModelInfo?.isR1FormatRequired}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
let modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
let modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo = { ...modelInfo, isR1FormatRequired: isChecked }
|
||||
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
Enable R1 messages format
|
||||
</VSCodeCheckbox>
|
||||
@@ -230,34 +243,38 @@ export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICo
|
||||
<div style={{ display: "flex", gap: 10, marginTop: "5px" }}>
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.openAiModelInfo?.contextWindow
|
||||
? apiConfiguration.openAiModelInfo.contextWindow.toString()
|
||||
openAiModelInfo?.contextWindow
|
||||
? openAiModelInfo.contextWindow.toString()
|
||||
: (openAiModelInfoSaneDefaults.contextWindow?.toString() ?? "")
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
const modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo.contextWindow = Number(value)
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Context Window Size</span>
|
||||
</DebouncedTextField>
|
||||
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.openAiModelInfo?.maxTokens
|
||||
? apiConfiguration.openAiModelInfo.maxTokens.toString()
|
||||
openAiModelInfo?.maxTokens
|
||||
? openAiModelInfo.maxTokens.toString()
|
||||
: (openAiModelInfoSaneDefaults.maxTokens?.toString() ?? "")
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
const modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo.maxTokens = Number(value)
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Max Output Tokens</span>
|
||||
</DebouncedTextField>
|
||||
@@ -266,34 +283,38 @@ export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICo
|
||||
<div style={{ display: "flex", gap: 10, marginTop: "5px" }}>
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.openAiModelInfo?.inputPrice
|
||||
? apiConfiguration.openAiModelInfo.inputPrice.toString()
|
||||
openAiModelInfo?.inputPrice
|
||||
? openAiModelInfo.inputPrice.toString()
|
||||
: (openAiModelInfoSaneDefaults.inputPrice?.toString() ?? "")
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
const modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo.inputPrice = Number(value)
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Input Price / 1M tokens</span>
|
||||
</DebouncedTextField>
|
||||
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.openAiModelInfo?.outputPrice
|
||||
? apiConfiguration.openAiModelInfo.outputPrice.toString()
|
||||
openAiModelInfo?.outputPrice
|
||||
? openAiModelInfo.outputPrice.toString()
|
||||
: (openAiModelInfoSaneDefaults.outputPrice?.toString() ?? "")
|
||||
}
|
||||
style={{ flex: 1 }}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
const modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
modelInfo.outputPrice = Number(value)
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Output Price / 1M tokens</span>
|
||||
</DebouncedTextField>
|
||||
@@ -302,14 +323,12 @@ export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICo
|
||||
<div style={{ display: "flex", gap: 10, marginTop: "5px" }}>
|
||||
<DebouncedTextField
|
||||
initialValue={
|
||||
apiConfiguration?.openAiModelInfo?.temperature
|
||||
? apiConfiguration.openAiModelInfo.temperature.toString()
|
||||
openAiModelInfo?.temperature
|
||||
? openAiModelInfo.temperature.toString()
|
||||
: (openAiModelInfoSaneDefaults.temperature?.toString() ?? "")
|
||||
}
|
||||
onChange={(value) => {
|
||||
const modelInfo = apiConfiguration?.openAiModelInfo
|
||||
? apiConfiguration.openAiModelInfo
|
||||
: { ...openAiModelInfoSaneDefaults }
|
||||
const modelInfo = openAiModelInfo ? openAiModelInfo : { ...openAiModelInfoSaneDefaults }
|
||||
|
||||
const shouldPreserveFormat = value.endsWith(".") || (value.includes(".") && value.endsWith("0"))
|
||||
|
||||
@@ -320,7 +339,11 @@ export const OpenAICompatibleProvider = ({ showModelOptions, isPopup }: OpenAICo
|
||||
? (value as any)
|
||||
: parseFloat(value)
|
||||
|
||||
handleFieldChange("openAiModelInfo", modelInfo)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeOpenAiModelInfo", act: "actModeOpenAiModelInfo" },
|
||||
modelInfo,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Temperature</span>
|
||||
</DebouncedTextField>
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the OpenAINativeProvider component
|
||||
@@ -12,17 +13,18 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface OpenAINativeProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The OpenAI (native) provider configuration component
|
||||
*/
|
||||
export const OpenAINativeProvider = ({ showModelOptions, isPopup }: OpenAINativeProviderProps) => {
|
||||
export const OpenAINativeProvider = ({ showModelOptions, isPopup, currentMode }: OpenAINativeProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +40,13 @@ export const OpenAINativeProvider = ({ showModelOptions, isPopup }: OpenAINative
|
||||
<ModelSelector
|
||||
models={openAiNativeModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -10,6 +10,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"
|
||||
|
||||
/**
|
||||
* Component to display OpenRouter balance information
|
||||
@@ -53,14 +54,14 @@ const OpenRouterBalanceDisplay = ({ apiKey }: { apiKey: string }) => {
|
||||
interface OpenRouterProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
uriScheme?: string
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The OpenRouter provider configuration component
|
||||
*/
|
||||
export const OpenRouterProvider = ({ showModelOptions, isPopup, uriScheme }: OpenRouterProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
export const OpenRouterProvider = ({ showModelOptions, isPopup, currentMode }: OpenRouterProviderProps) => {
|
||||
const { apiConfiguration, uriScheme } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const [providerSortingSelected, setProviderSortingSelected] = useState(!!apiConfiguration?.openRouterProviderSorting)
|
||||
@@ -142,7 +143,7 @@ export const OpenRouterProvider = ({ showModelOptions, isPopup, uriScheme }: Ope
|
||||
</div>
|
||||
)}
|
||||
|
||||
<OpenRouterModelPicker isPopup={isPopup} />
|
||||
<OpenRouterModelPicker isPopup={isPopup} currentMode={currentMode} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -8,6 +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"
|
||||
|
||||
const SUPPORTED_THINKING_MODELS = [
|
||||
"qwen3-235b-a22b",
|
||||
@@ -28,17 +29,18 @@ const SUPPORTED_THINKING_MODELS = [
|
||||
interface QwenProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Alibaba Qwen provider configuration component
|
||||
*/
|
||||
export const QwenProvider = ({ showModelOptions, isPopup }: QwenProviderProps) => {
|
||||
export const QwenProvider = ({ showModelOptions, isPopup, currentMode }: QwenProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
// Determine which models to use based on API line selection
|
||||
const qwenModels = apiConfiguration?.qwenApiLine === "china" ? mainlandQwenModels : internationalQwenModels
|
||||
@@ -83,13 +85,19 @@ export const QwenProvider = ({ showModelOptions, isPopup }: QwenProviderProps) =
|
||||
<ModelSelector
|
||||
models={qwenModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
zIndex={DROPDOWN_Z_INDEX - 2}
|
||||
/>
|
||||
|
||||
{SUPPORTED_THINKING_MODELS.includes(selectedModelId) && (
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} />
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import RequestyModelPicker from "../RequestyModelPicker"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
@@ -9,12 +10,13 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface RequestyProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Requesty provider configuration component
|
||||
*/
|
||||
export const RequestyProvider = ({ showModelOptions, isPopup }: RequestyProviderProps) => {
|
||||
export const RequestyProvider = ({ showModelOptions, isPopup, currentMode }: RequestyProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
@@ -27,7 +29,7 @@ export const RequestyProvider = ({ showModelOptions, isPopup }: RequestyProvider
|
||||
signupUrl="https://app.requesty.ai/manage-api"
|
||||
/>
|
||||
|
||||
{showModelOptions && <RequestyModelPicker isPopup={isPopup} />}
|
||||
{showModelOptions && <RequestyModelPicker isPopup={isPopup} currentMode={currentMode} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the SambanovaProvider component
|
||||
@@ -12,17 +13,18 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface SambanovaProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The SambaNova provider configuration component
|
||||
*/
|
||||
export const SambanovaProvider = ({ showModelOptions, isPopup }: SambanovaProviderProps) => {
|
||||
export const SambanovaProvider = ({ showModelOptions, isPopup, currentMode }: SambanovaProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -38,7 +40,13 @@ export const SambanovaProvider = ({ showModelOptions, isPopup }: SambanovaProvid
|
||||
<ModelSelector
|
||||
models={sambanovaModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -6,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the SapAiCoreProvider component
|
||||
@@ -13,16 +14,17 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface SapAiCoreProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The SAP AI Core provider configuration component
|
||||
*/
|
||||
export const SapAiCoreProvider = ({ showModelOptions, isPopup }: SapAiCoreProviderProps) => {
|
||||
export const SapAiCoreProvider = ({ showModelOptions, isPopup, currentMode }: SapAiCoreProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
|
||||
@@ -97,7 +99,13 @@ export const SapAiCoreProvider = ({ showModelOptions, isPopup }: SapAiCoreProvid
|
||||
<ModelSelector
|
||||
models={sapAiCoreModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ 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"
|
||||
|
||||
/**
|
||||
* Props for the TogetherProvider component
|
||||
@@ -10,14 +12,17 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface TogetherProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
/**
|
||||
* The Together provider configuration component
|
||||
*/
|
||||
export const TogetherProvider = ({ showModelOptions, isPopup }: TogetherProviderProps) => {
|
||||
export const TogetherProvider = ({ showModelOptions, isPopup, currentMode }: TogetherProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { togetherModelId } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -27,8 +32,10 @@ export const TogetherProvider = ({ showModelOptions, isPopup }: TogetherProvider
|
||||
providerName="Together"
|
||||
/>
|
||||
<DebouncedTextField
|
||||
initialValue={apiConfiguration?.togetherModelId || ""}
|
||||
onChange={(value) => handleFieldChange("togetherModelId", value)}
|
||||
initialValue={togetherModelId || ""}
|
||||
onChange={(value) =>
|
||||
handleModeFieldChange({ plan: "planModeTogetherModelId", act: "actModeTogetherModelId" }, value, currentMode)
|
||||
}
|
||||
style={{ width: "100%" }}
|
||||
placeholder={"Enter Model ID..."}>
|
||||
<span style={{ fontWeight: 500 }}>Model ID</span>
|
||||
|
||||
@@ -7,11 +7,19 @@ import * as vscodemodels from "vscode"
|
||||
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"
|
||||
|
||||
export const VSCodeLmProvider = () => {
|
||||
interface VSCodeLmProviderProps {
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
export const VSCodeLmProvider = ({ currentMode }: VSCodeLmProviderProps) => {
|
||||
const [vsCodeLmModels, setVsCodeLmModels] = useState<vscodemodels.LanguageModelChatSelector[]>([])
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const { vsCodeLmModelSelector } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
// Poll VS Code LM models
|
||||
const requestVsCodeLmModels = useCallback(async () => {
|
||||
@@ -42,8 +50,8 @@ export const VSCodeLmProvider = () => {
|
||||
<VSCodeDropdown
|
||||
id="vscode-lm-model"
|
||||
value={
|
||||
apiConfiguration?.vsCodeLmModelSelector
|
||||
? `${apiConfiguration.vsCodeLmModelSelector.vendor ?? ""}/${apiConfiguration.vsCodeLmModelSelector.family ?? ""}`
|
||||
vsCodeLmModelSelector
|
||||
? `${vsCodeLmModelSelector.vendor ?? ""}/${vsCodeLmModelSelector.family ?? ""}`
|
||||
: ""
|
||||
}
|
||||
onChange={(e) => {
|
||||
@@ -53,7 +61,11 @@ export const VSCodeLmProvider = () => {
|
||||
}
|
||||
const [vendor, family] = value.split("/")
|
||||
|
||||
handleFieldChange("vsCodeLmModelSelector", { vendor, family })
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeVsCodeLmModelSelector", act: "actModeVsCodeLmModelSelector" },
|
||||
{ vendor, family },
|
||||
currentMode,
|
||||
)
|
||||
}}
|
||||
style={{ width: "100%" }}>
|
||||
<VSCodeOption value="">Select a model...</VSCodeOption>
|
||||
|
||||
@@ -8,6 +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"
|
||||
|
||||
/**
|
||||
* Props for the VertexProvider component
|
||||
@@ -15,6 +16,7 @@ import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandler
|
||||
interface VertexProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
// Vertex models that support thinking
|
||||
@@ -30,12 +32,12 @@ const SUPPORTED_THINKING_MODELS = [
|
||||
/**
|
||||
* The GCP Vertex AI provider configuration component
|
||||
*/
|
||||
export const VertexProvider = ({ showModelOptions, isPopup }: VertexProviderProps) => {
|
||||
export const VertexProvider = ({ showModelOptions, isPopup, currentMode }: VertexProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
// Determine which models to use based on region
|
||||
const modelsToUse = apiConfiguration?.vertexRegion === "global" ? vertexGlobalModels : vertexModels
|
||||
@@ -98,13 +100,19 @@ export const VertexProvider = ({ showModelOptions, isPopup }: VertexProviderProp
|
||||
<ModelSelector
|
||||
models={modelsToUse}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
zIndex={DROPDOWN_Z_INDEX - 2}
|
||||
/>
|
||||
|
||||
{SUPPORTED_THINKING_MODELS.includes(selectedModelId) && (
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} />
|
||||
<ThinkingBudgetSlider maxBudget={selectedModelInfo.thinkingConfig?.maxBudget} currentMode={currentMode} />
|
||||
)}
|
||||
|
||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
|
||||
|
||||
@@ -4,10 +4,11 @@ import { useState, useEffect } from "react"
|
||||
import { ApiKeyField } from "../common/ApiKeyField"
|
||||
import { ModelSelector, DropdownContainer } from "../common/ModelSelector"
|
||||
import { ModelInfoView } from "../common/ModelInfoView"
|
||||
import { normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { getModeSpecificFields, normalizeApiConfiguration } from "../utils/providerUtils"
|
||||
import { DROPDOWN_Z_INDEX } from "../ApiOptions"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
/**
|
||||
* Props for the XaiProvider component
|
||||
@@ -15,17 +16,20 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
interface XaiProviderProps {
|
||||
showModelOptions: boolean
|
||||
isPopup?: boolean
|
||||
currentMode: Mode
|
||||
}
|
||||
|
||||
export const XaiProvider = ({ showModelOptions, isPopup }: XaiProviderProps) => {
|
||||
export const XaiProvider = ({ showModelOptions, isPopup, currentMode }: XaiProviderProps) => {
|
||||
const { apiConfiguration } = useExtensionState()
|
||||
const { handleFieldChange } = useApiConfigurationHandlers()
|
||||
const { handleFieldChange, handleModeFieldChange } = useApiConfigurationHandlers()
|
||||
|
||||
const modeFields = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
// Get the normalized configuration
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
|
||||
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration, currentMode)
|
||||
|
||||
// Local state for reasoning effort toggle
|
||||
const [reasoningEffortSelected, setReasoningEffortSelected] = useState(!!apiConfiguration?.reasoningEffort)
|
||||
const [reasoningEffortSelected, setReasoningEffortSelected] = useState(!!modeFields.reasoningEffort)
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -54,7 +58,13 @@ export const XaiProvider = ({ showModelOptions, isPopup }: XaiProviderProps) =>
|
||||
<ModelSelector
|
||||
models={xaiModels}
|
||||
selectedModelId={selectedModelId}
|
||||
onChange={(e: any) => handleFieldChange("apiModelId", e.target.value)}
|
||||
onChange={(e: any) =>
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeApiModelId", act: "actModeApiModelId" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
label="Model"
|
||||
/>
|
||||
|
||||
@@ -67,7 +77,11 @@ export const XaiProvider = ({ showModelOptions, isPopup }: XaiProviderProps) =>
|
||||
const isChecked = e.target.checked === true
|
||||
setReasoningEffortSelected(isChecked)
|
||||
if (!isChecked) {
|
||||
handleFieldChange("reasoningEffort", "")
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeReasoningEffort", act: "actModeReasoningEffort" },
|
||||
"",
|
||||
currentMode,
|
||||
)
|
||||
}
|
||||
}}>
|
||||
Modify reasoning effort
|
||||
@@ -82,9 +96,13 @@ export const XaiProvider = ({ showModelOptions, isPopup }: XaiProviderProps) =>
|
||||
<VSCodeDropdown
|
||||
id="reasoning-effort-dropdown"
|
||||
style={{ width: "100%", marginTop: 3 }}
|
||||
value={apiConfiguration?.reasoningEffort || "high"}
|
||||
value={modeFields.reasoningEffort || "high"}
|
||||
onChange={(e: any) => {
|
||||
handleFieldChange("reasoningEffort", e.target.value)
|
||||
handleModeFieldChange(
|
||||
{ plan: "planModeReasoningEffort", act: "actModeReasoningEffort" },
|
||||
e.target.value,
|
||||
currentMode,
|
||||
)
|
||||
}}>
|
||||
<VSCodeOption value="low">low</VSCodeOption>
|
||||
<VSCodeOption value="high">high</VSCodeOption>
|
||||
|
||||
@@ -5,19 +5,19 @@ import Section from "../Section"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { StateServiceClient } from "@/services/grpc-client"
|
||||
import { UpdateSettingsRequest } from "@shared/proto/state"
|
||||
import { useState } from "react"
|
||||
import { syncModeConfigurations } from "../utils/providerUtils"
|
||||
import { useApiConfigurationHandlers } from "../utils/useApiConfigurationHandlers"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
interface ApiConfigurationSectionProps {
|
||||
isSwitchingMode: boolean
|
||||
handlePlanActModeChange: (mode: "plan" | "act") => Promise<void>
|
||||
renderSectionHeader: (tabId: string) => JSX.Element | null
|
||||
}
|
||||
|
||||
const ApiConfigurationSection = ({
|
||||
isSwitchingMode,
|
||||
handlePlanActModeChange,
|
||||
renderSectionHeader,
|
||||
}: ApiConfigurationSectionProps) => {
|
||||
const { planActSeparateModelsSetting, chatSettings } = useExtensionState()
|
||||
const ApiConfigurationSection = ({ renderSectionHeader }: ApiConfigurationSectionProps) => {
|
||||
const { planActSeparateModelsSetting, chatSettings, apiConfiguration } = useExtensionState()
|
||||
const [currentTab, setCurrentTab] = useState<Mode>(chatSettings.mode)
|
||||
const { handleFieldsChange } = useApiConfigurationHandlers()
|
||||
return (
|
||||
<div>
|
||||
{renderSectionHeader("api-config")}
|
||||
@@ -27,34 +27,34 @@ const ApiConfigurationSection = ({
|
||||
<div className="rounded-md mb-5 bg-[var(--vscode-panel-background)]">
|
||||
<div className="flex gap-[1px] mb-[10px] -mt-2 border-0 border-b border-solid border-[var(--vscode-panel-border)]">
|
||||
<TabButton
|
||||
isActive={chatSettings.mode === "plan"}
|
||||
onClick={() => handlePlanActModeChange("plan")}
|
||||
disabled={isSwitchingMode}
|
||||
isActive={currentTab === "plan"}
|
||||
onClick={() => setCurrentTab("plan")}
|
||||
disabled={currentTab === "plan"}
|
||||
style={{
|
||||
opacity: isSwitchingMode ? 0.6 : 1,
|
||||
cursor: isSwitchingMode ? "not-allowed" : "pointer",
|
||||
opacity: 1,
|
||||
cursor: "pointer",
|
||||
}}>
|
||||
{isSwitchingMode && chatSettings.mode === "act" ? "Switching..." : "Plan Mode"}
|
||||
Plan Mode
|
||||
</TabButton>
|
||||
<TabButton
|
||||
isActive={chatSettings.mode === "act"}
|
||||
onClick={() => handlePlanActModeChange("act")}
|
||||
disabled={isSwitchingMode}
|
||||
isActive={currentTab === "act"}
|
||||
onClick={() => setCurrentTab("act")}
|
||||
disabled={currentTab === "act"}
|
||||
style={{
|
||||
opacity: isSwitchingMode ? 0.6 : 1,
|
||||
cursor: isSwitchingMode ? "not-allowed" : "pointer",
|
||||
opacity: 1,
|
||||
cursor: "pointer",
|
||||
}}>
|
||||
{isSwitchingMode && chatSettings.mode === "plan" ? "Switching..." : "Act Mode"}
|
||||
Act Mode
|
||||
</TabButton>
|
||||
</div>
|
||||
|
||||
{/* Content container */}
|
||||
<div className="-mb-3">
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode={currentTab} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<ApiOptions showModelOptions={true} />
|
||||
<ApiOptions showModelOptions={true} currentMode={chatSettings.mode} />
|
||||
)}
|
||||
|
||||
<div className="mb-[5px]">
|
||||
@@ -64,6 +64,10 @@ const ApiConfigurationSection = ({
|
||||
onChange={async (e: any) => {
|
||||
const checked = e.target.checked === true
|
||||
try {
|
||||
// If unchecking the toggle, wait a bit for state to update, then sync configurations
|
||||
if (!checked) {
|
||||
await syncModeConfigurations(apiConfiguration, currentTab, handleFieldsChange)
|
||||
}
|
||||
await StateServiceClient.updateSettings(
|
||||
UpdateSettingsRequest.create({
|
||||
planActSeparateModelsSetting: checked,
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
groqModels,
|
||||
groqDefaultModelId,
|
||||
} from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
/**
|
||||
* Interface for normalized API configuration
|
||||
@@ -62,9 +63,13 @@ export interface NormalizedApiConfig {
|
||||
/**
|
||||
* Normalizes API configuration to ensure consistent values
|
||||
*/
|
||||
export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration): NormalizedApiConfig {
|
||||
const provider = apiConfiguration?.apiProvider || "anthropic"
|
||||
const modelId = apiConfiguration?.apiModelId
|
||||
export function normalizeApiConfiguration(
|
||||
apiConfiguration: ApiConfiguration | undefined,
|
||||
currentMode: Mode,
|
||||
): NormalizedApiConfig {
|
||||
const provider =
|
||||
(currentMode === "plan" ? apiConfiguration?.planModeApiProvider : apiConfiguration?.actModeApiProvider) || "anthropic"
|
||||
const modelId = currentMode === "plan" ? apiConfiguration?.planModeApiModelId : apiConfiguration?.actModeApiModelId
|
||||
|
||||
const getProviderData = (models: Record<string, ModelInfo>, defaultId: string) => {
|
||||
let selectedModelId: string
|
||||
@@ -89,8 +94,15 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration):
|
||||
case "claude-code":
|
||||
return getProviderData(claudeCodeModels, claudeCodeDefaultModelId)
|
||||
case "bedrock":
|
||||
if (apiConfiguration?.awsBedrockCustomSelected) {
|
||||
const baseModelId = apiConfiguration.awsBedrockCustomModelBaseId
|
||||
const awsBedrockCustomSelected =
|
||||
currentMode === "plan"
|
||||
? apiConfiguration?.planModeAwsBedrockCustomSelected
|
||||
: apiConfiguration?.actModeAwsBedrockCustomSelected
|
||||
if (awsBedrockCustomSelected) {
|
||||
const baseModelId =
|
||||
currentMode === "plan"
|
||||
? apiConfiguration?.planModeAwsBedrockCustomModelBaseId
|
||||
: apiConfiguration?.actModeAwsBedrockCustomModelBaseId
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: modelId || bedrockDefaultModelId,
|
||||
@@ -118,69 +130,107 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration):
|
||||
case "asksage":
|
||||
return getProviderData(askSageModels, askSageDefaultModelId)
|
||||
case "openrouter":
|
||||
const openRouterModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeOpenRouterModelId : apiConfiguration?.actModeOpenRouterModelId
|
||||
const openRouterModelInfo =
|
||||
currentMode === "plan"
|
||||
? apiConfiguration?.planModeOpenRouterModelInfo
|
||||
: apiConfiguration?.actModeOpenRouterModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.openRouterModelId || openRouterDefaultModelId,
|
||||
selectedModelInfo: apiConfiguration?.openRouterModelInfo || openRouterDefaultModelInfo,
|
||||
selectedModelId: openRouterModelId || openRouterDefaultModelId,
|
||||
selectedModelInfo: openRouterModelInfo || openRouterDefaultModelInfo,
|
||||
}
|
||||
case "requesty":
|
||||
const requestyModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeRequestyModelId : apiConfiguration?.actModeRequestyModelId
|
||||
const requestyModelInfo =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeRequestyModelInfo : apiConfiguration?.actModeRequestyModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.requestyModelId || requestyDefaultModelId,
|
||||
selectedModelInfo: apiConfiguration?.requestyModelInfo || requestyDefaultModelInfo,
|
||||
selectedModelId: requestyModelId || requestyDefaultModelId,
|
||||
selectedModelInfo: requestyModelInfo || requestyDefaultModelInfo,
|
||||
}
|
||||
case "cline":
|
||||
const openRouterModelId = apiConfiguration?.openRouterModelId || openRouterDefaultModelId
|
||||
const openRouterModelInfo = apiConfiguration?.openRouterModelInfo || openRouterDefaultModelInfo
|
||||
const clineOpenRouterModelId =
|
||||
(currentMode === "plan"
|
||||
? apiConfiguration?.planModeOpenRouterModelId
|
||||
: apiConfiguration?.actModeOpenRouterModelId) || openRouterDefaultModelId
|
||||
const clineOpenRouterModelInfo =
|
||||
(currentMode === "plan"
|
||||
? apiConfiguration?.planModeOpenRouterModelInfo
|
||||
: apiConfiguration?.actModeOpenRouterModelInfo) || openRouterDefaultModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: openRouterModelId,
|
||||
selectedModelInfo: openRouterModelInfo,
|
||||
selectedModelId: clineOpenRouterModelId,
|
||||
selectedModelInfo: clineOpenRouterModelInfo,
|
||||
}
|
||||
case "openai":
|
||||
const openAiModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeOpenAiModelId : apiConfiguration?.actModeOpenAiModelId
|
||||
const openAiModelInfo =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeOpenAiModelInfo : apiConfiguration?.actModeOpenAiModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.openAiModelId || "",
|
||||
selectedModelInfo: apiConfiguration?.openAiModelInfo || openAiModelInfoSaneDefaults,
|
||||
selectedModelId: openAiModelId || "",
|
||||
selectedModelInfo: openAiModelInfo || openAiModelInfoSaneDefaults,
|
||||
}
|
||||
case "ollama":
|
||||
const ollamaModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeOllamaModelId : apiConfiguration?.actModeOllamaModelId
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.ollamaModelId || "",
|
||||
selectedModelId: ollamaModelId || "",
|
||||
selectedModelInfo: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
case "lmstudio":
|
||||
const lmStudioModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeLmStudioModelId : apiConfiguration?.actModeLmStudioModelId
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.lmStudioModelId || "",
|
||||
selectedModelId: lmStudioModelId || "",
|
||||
selectedModelInfo: openAiModelInfoSaneDefaults,
|
||||
}
|
||||
case "vscode-lm":
|
||||
const vsCodeLmModelSelector =
|
||||
currentMode === "plan"
|
||||
? apiConfiguration?.planModeVsCodeLmModelSelector
|
||||
: apiConfiguration?.actModeVsCodeLmModelSelector
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.vsCodeLmModelSelector
|
||||
? `${apiConfiguration.vsCodeLmModelSelector.vendor}/${apiConfiguration.vsCodeLmModelSelector.family}`
|
||||
: "",
|
||||
selectedModelId: vsCodeLmModelSelector ? `${vsCodeLmModelSelector.vendor}/${vsCodeLmModelSelector.family}` : "",
|
||||
selectedModelInfo: {
|
||||
...openAiModelInfoSaneDefaults,
|
||||
supportsImages: false, // VSCode LM API currently doesn't support images
|
||||
},
|
||||
}
|
||||
case "litellm":
|
||||
const liteLlmModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeLiteLlmModelId : apiConfiguration?.actModeLiteLlmModelId
|
||||
const liteLlmModelInfo =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeLiteLlmModelInfo : apiConfiguration?.actModeLiteLlmModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.liteLlmModelId || "",
|
||||
selectedModelInfo: apiConfiguration?.liteLlmModelInfo || liteLlmModelInfoSaneDefaults,
|
||||
selectedModelId: liteLlmModelId || "",
|
||||
selectedModelInfo: liteLlmModelInfo || liteLlmModelInfoSaneDefaults,
|
||||
}
|
||||
case "xai":
|
||||
return getProviderData(xaiModels, xaiDefaultModelId)
|
||||
case "moonshot":
|
||||
return getProviderData(moonshotModels, moonshotDefaultModelId)
|
||||
case "huggingface":
|
||||
const huggingFaceModelId =
|
||||
currentMode === "plan"
|
||||
? apiConfiguration?.planModeHuggingFaceModelId
|
||||
: apiConfiguration?.actModeHuggingFaceModelId
|
||||
const huggingFaceModelInfo =
|
||||
currentMode === "plan"
|
||||
? apiConfiguration?.planModeHuggingFaceModelInfo
|
||||
: apiConfiguration?.actModeHuggingFaceModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.huggingFaceModelId || huggingFaceDefaultModelId,
|
||||
selectedModelInfo: apiConfiguration?.huggingFaceModelInfo || huggingFaceModels[huggingFaceDefaultModelId],
|
||||
selectedModelId: huggingFaceModelId || huggingFaceDefaultModelId,
|
||||
selectedModelInfo: huggingFaceModelInfo || huggingFaceModels[huggingFaceDefaultModelId],
|
||||
}
|
||||
case "nebius":
|
||||
return getProviderData(nebiusModels, nebiusDefaultModelId)
|
||||
@@ -189,13 +239,15 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration):
|
||||
case "cerebras":
|
||||
return getProviderData(cerebrasModels, cerebrasDefaultModelId)
|
||||
case "groq":
|
||||
const result = {
|
||||
const groqModelId =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeGroqModelId : apiConfiguration?.actModeGroqModelId
|
||||
const groqModelInfo =
|
||||
currentMode === "plan" ? apiConfiguration?.planModeGroqModelInfo : apiConfiguration?.actModeGroqModelInfo
|
||||
return {
|
||||
selectedProvider: provider,
|
||||
selectedModelId: apiConfiguration?.groqModelId || groqDefaultModelId,
|
||||
selectedModelInfo: apiConfiguration?.groqModelInfo || groqModels[groqDefaultModelId],
|
||||
selectedModelId: groqModelId || groqDefaultModelId,
|
||||
selectedModelInfo: groqModelInfo || groqModels[groqDefaultModelId],
|
||||
}
|
||||
|
||||
return result
|
||||
case "sapaicore":
|
||||
return getProviderData(sapAiCoreModels, sapAiCoreDefaultModelId)
|
||||
default:
|
||||
@@ -203,6 +255,231 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration):
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets mode-specific field values from API configuration
|
||||
* @param apiConfiguration The API configuration object
|
||||
* @param mode The current mode ("plan" or "act")
|
||||
* @returns Object containing mode-specific field values for clean destructuring
|
||||
*/
|
||||
export function getModeSpecificFields(apiConfiguration: ApiConfiguration | undefined, mode: Mode) {
|
||||
if (!apiConfiguration) {
|
||||
return {
|
||||
// Core fields
|
||||
apiProvider: undefined,
|
||||
apiModelId: undefined,
|
||||
|
||||
// Provider-specific model IDs
|
||||
togetherModelId: undefined,
|
||||
fireworksModelId: undefined,
|
||||
lmStudioModelId: undefined,
|
||||
ollamaModelId: undefined,
|
||||
liteLlmModelId: undefined,
|
||||
requestyModelId: undefined,
|
||||
openAiModelId: undefined,
|
||||
openRouterModelId: undefined,
|
||||
groqModelId: undefined,
|
||||
huggingFaceModelId: undefined,
|
||||
|
||||
// Model info objects
|
||||
openAiModelInfo: undefined,
|
||||
liteLlmModelInfo: undefined,
|
||||
openRouterModelInfo: undefined,
|
||||
requestyModelInfo: undefined,
|
||||
groqModelInfo: undefined,
|
||||
huggingFaceModelInfo: undefined,
|
||||
vsCodeLmModelSelector: undefined,
|
||||
|
||||
// AWS Bedrock fields
|
||||
awsBedrockCustomSelected: undefined,
|
||||
awsBedrockCustomModelBaseId: undefined,
|
||||
|
||||
// Other mode-specific fields
|
||||
thinkingBudgetTokens: undefined,
|
||||
reasoningEffort: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// Core fields
|
||||
apiProvider: mode === "plan" ? apiConfiguration.planModeApiProvider : apiConfiguration.actModeApiProvider,
|
||||
apiModelId: mode === "plan" ? apiConfiguration.planModeApiModelId : apiConfiguration.actModeApiModelId,
|
||||
|
||||
// Provider-specific model IDs
|
||||
togetherModelId: mode === "plan" ? apiConfiguration.planModeTogetherModelId : apiConfiguration.actModeTogetherModelId,
|
||||
fireworksModelId: mode === "plan" ? apiConfiguration.planModeFireworksModelId : apiConfiguration.actModeFireworksModelId,
|
||||
lmStudioModelId: mode === "plan" ? apiConfiguration.planModeLmStudioModelId : apiConfiguration.actModeLmStudioModelId,
|
||||
ollamaModelId: mode === "plan" ? apiConfiguration.planModeOllamaModelId : apiConfiguration.actModeOllamaModelId,
|
||||
liteLlmModelId: mode === "plan" ? apiConfiguration.planModeLiteLlmModelId : apiConfiguration.actModeLiteLlmModelId,
|
||||
requestyModelId: mode === "plan" ? apiConfiguration.planModeRequestyModelId : apiConfiguration.actModeRequestyModelId,
|
||||
openAiModelId: mode === "plan" ? apiConfiguration.planModeOpenAiModelId : apiConfiguration.actModeOpenAiModelId,
|
||||
openRouterModelId:
|
||||
mode === "plan" ? apiConfiguration.planModeOpenRouterModelId : apiConfiguration.actModeOpenRouterModelId,
|
||||
groqModelId: mode === "plan" ? apiConfiguration.planModeGroqModelId : apiConfiguration.actModeGroqModelId,
|
||||
huggingFaceModelId:
|
||||
mode === "plan" ? apiConfiguration.planModeHuggingFaceModelId : apiConfiguration.actModeHuggingFaceModelId,
|
||||
|
||||
// Model info objects
|
||||
openAiModelInfo: mode === "plan" ? apiConfiguration.planModeOpenAiModelInfo : apiConfiguration.actModeOpenAiModelInfo,
|
||||
liteLlmModelInfo: mode === "plan" ? apiConfiguration.planModeLiteLlmModelInfo : apiConfiguration.actModeLiteLlmModelInfo,
|
||||
openRouterModelInfo:
|
||||
mode === "plan" ? apiConfiguration.planModeOpenRouterModelInfo : apiConfiguration.actModeOpenRouterModelInfo,
|
||||
requestyModelInfo:
|
||||
mode === "plan" ? apiConfiguration.planModeRequestyModelInfo : apiConfiguration.actModeRequestyModelInfo,
|
||||
groqModelInfo: mode === "plan" ? apiConfiguration.planModeGroqModelInfo : apiConfiguration.actModeGroqModelInfo,
|
||||
huggingFaceModelInfo:
|
||||
mode === "plan" ? apiConfiguration.planModeHuggingFaceModelInfo : apiConfiguration.actModeHuggingFaceModelInfo,
|
||||
vsCodeLmModelSelector:
|
||||
mode === "plan" ? apiConfiguration.planModeVsCodeLmModelSelector : apiConfiguration.actModeVsCodeLmModelSelector,
|
||||
|
||||
// AWS Bedrock fields
|
||||
awsBedrockCustomSelected:
|
||||
mode === "plan"
|
||||
? apiConfiguration.planModeAwsBedrockCustomSelected
|
||||
: apiConfiguration.actModeAwsBedrockCustomSelected,
|
||||
awsBedrockCustomModelBaseId:
|
||||
mode === "plan"
|
||||
? apiConfiguration.planModeAwsBedrockCustomModelBaseId
|
||||
: apiConfiguration.actModeAwsBedrockCustomModelBaseId,
|
||||
|
||||
// Other mode-specific fields
|
||||
thinkingBudgetTokens:
|
||||
mode === "plan" ? apiConfiguration.planModeThinkingBudgetTokens : apiConfiguration.actModeThinkingBudgetTokens,
|
||||
reasoningEffort: mode === "plan" ? apiConfiguration.planModeReasoningEffort : apiConfiguration.actModeReasoningEffort,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes mode configurations by copying the source mode's settings to both modes
|
||||
* This is used when the "Use different models for Plan and Act modes" toggle is unchecked
|
||||
*/
|
||||
export async function syncModeConfigurations(
|
||||
apiConfiguration: ApiConfiguration | undefined,
|
||||
sourceMode: Mode,
|
||||
handleFieldsChange: (updates: Partial<ApiConfiguration>) => Promise<void>,
|
||||
): Promise<void> {
|
||||
if (!apiConfiguration) return
|
||||
|
||||
const sourceFields = getModeSpecificFields(apiConfiguration, sourceMode)
|
||||
const { apiProvider } = sourceFields
|
||||
|
||||
if (!apiProvider) return
|
||||
|
||||
// Build the complete update object with both plan and act mode fields
|
||||
const updates: Partial<ApiConfiguration> = {
|
||||
// Always sync common fields
|
||||
planModeApiProvider: sourceFields.apiProvider,
|
||||
actModeApiProvider: sourceFields.apiProvider,
|
||||
planModeThinkingBudgetTokens: sourceFields.thinkingBudgetTokens,
|
||||
actModeThinkingBudgetTokens: sourceFields.thinkingBudgetTokens,
|
||||
planModeReasoningEffort: sourceFields.reasoningEffort,
|
||||
actModeReasoningEffort: sourceFields.reasoningEffort,
|
||||
}
|
||||
|
||||
// Handle provider-specific fields
|
||||
switch (apiProvider) {
|
||||
case "openrouter":
|
||||
case "cline":
|
||||
updates.planModeOpenRouterModelId = sourceFields.openRouterModelId
|
||||
updates.actModeOpenRouterModelId = sourceFields.openRouterModelId
|
||||
updates.planModeOpenRouterModelInfo = sourceFields.openRouterModelInfo
|
||||
updates.actModeOpenRouterModelInfo = sourceFields.openRouterModelInfo
|
||||
break
|
||||
|
||||
case "requesty":
|
||||
updates.planModeRequestyModelId = sourceFields.requestyModelId
|
||||
updates.actModeRequestyModelId = sourceFields.requestyModelId
|
||||
updates.planModeRequestyModelInfo = sourceFields.requestyModelInfo
|
||||
updates.actModeRequestyModelInfo = sourceFields.requestyModelInfo
|
||||
break
|
||||
|
||||
case "openai":
|
||||
updates.planModeOpenAiModelId = sourceFields.openAiModelId
|
||||
updates.actModeOpenAiModelId = sourceFields.openAiModelId
|
||||
updates.planModeOpenAiModelInfo = sourceFields.openAiModelInfo
|
||||
updates.actModeOpenAiModelInfo = sourceFields.openAiModelInfo
|
||||
break
|
||||
|
||||
case "ollama":
|
||||
updates.planModeOllamaModelId = sourceFields.ollamaModelId
|
||||
updates.actModeOllamaModelId = sourceFields.ollamaModelId
|
||||
break
|
||||
|
||||
case "lmstudio":
|
||||
updates.planModeLmStudioModelId = sourceFields.lmStudioModelId
|
||||
updates.actModeLmStudioModelId = sourceFields.lmStudioModelId
|
||||
break
|
||||
|
||||
case "vscode-lm":
|
||||
updates.planModeVsCodeLmModelSelector = sourceFields.vsCodeLmModelSelector
|
||||
updates.actModeVsCodeLmModelSelector = sourceFields.vsCodeLmModelSelector
|
||||
break
|
||||
|
||||
case "litellm":
|
||||
updates.planModeLiteLlmModelId = sourceFields.liteLlmModelId
|
||||
updates.actModeLiteLlmModelId = sourceFields.liteLlmModelId
|
||||
updates.planModeLiteLlmModelInfo = sourceFields.liteLlmModelInfo
|
||||
updates.actModeLiteLlmModelInfo = sourceFields.liteLlmModelInfo
|
||||
break
|
||||
|
||||
case "groq":
|
||||
updates.planModeGroqModelId = sourceFields.groqModelId
|
||||
updates.actModeGroqModelId = sourceFields.groqModelId
|
||||
updates.planModeGroqModelInfo = sourceFields.groqModelInfo
|
||||
updates.actModeGroqModelInfo = sourceFields.groqModelInfo
|
||||
break
|
||||
|
||||
case "huggingface":
|
||||
updates.planModeHuggingFaceModelId = sourceFields.huggingFaceModelId
|
||||
updates.actModeHuggingFaceModelId = sourceFields.huggingFaceModelId
|
||||
updates.planModeHuggingFaceModelInfo = sourceFields.huggingFaceModelInfo
|
||||
updates.actModeHuggingFaceModelInfo = sourceFields.huggingFaceModelInfo
|
||||
break
|
||||
|
||||
case "together":
|
||||
updates.planModeTogetherModelId = sourceFields.togetherModelId
|
||||
updates.actModeTogetherModelId = sourceFields.togetherModelId
|
||||
break
|
||||
|
||||
case "fireworks":
|
||||
updates.planModeFireworksModelId = sourceFields.fireworksModelId
|
||||
updates.actModeFireworksModelId = sourceFields.fireworksModelId
|
||||
break
|
||||
|
||||
case "bedrock":
|
||||
updates.planModeApiModelId = sourceFields.apiModelId
|
||||
updates.actModeApiModelId = sourceFields.apiModelId
|
||||
updates.planModeAwsBedrockCustomSelected = sourceFields.awsBedrockCustomSelected
|
||||
updates.actModeAwsBedrockCustomSelected = sourceFields.awsBedrockCustomSelected
|
||||
updates.planModeAwsBedrockCustomModelBaseId = sourceFields.awsBedrockCustomModelBaseId
|
||||
updates.actModeAwsBedrockCustomModelBaseId = sourceFields.awsBedrockCustomModelBaseId
|
||||
break
|
||||
|
||||
// Providers that use apiProvider + apiModelId fields
|
||||
case "anthropic":
|
||||
case "claude-code":
|
||||
case "vertex":
|
||||
case "gemini":
|
||||
case "openai-native":
|
||||
case "deepseek":
|
||||
case "qwen":
|
||||
case "doubao":
|
||||
case "mistral":
|
||||
case "asksage":
|
||||
case "xai":
|
||||
case "nebius":
|
||||
case "sambanova":
|
||||
case "cerebras":
|
||||
case "sapaicore":
|
||||
default:
|
||||
updates.planModeApiModelId = sourceFields.apiModelId
|
||||
updates.actModeApiModelId = sourceFields.apiModelId
|
||||
break
|
||||
}
|
||||
|
||||
// Make the atomic update
|
||||
await handleFieldsChange(updates)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OpenRouter authentication URL
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { ModelsServiceClient } from "@/services/grpc-client"
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
import { convertApiConfigurationToProto } from "@shared/proto-conversions/models/api-configuration-conversion"
|
||||
import { UpdateApiConfigurationRequest } from "@shared/proto/models"
|
||||
import { useCallback } from "react"
|
||||
|
||||
export const useApiConfigurationHandlers = () => {
|
||||
const { apiConfiguration, uriScheme } = useExtensionState()
|
||||
const { apiConfiguration, planActSeparateModelsSetting } = useExtensionState()
|
||||
|
||||
/**
|
||||
* Updates a single field in the API configuration.
|
||||
*
|
||||
@@ -17,24 +19,19 @@ export const useApiConfigurationHandlers = () => {
|
||||
* @param field - The field key to update
|
||||
* @param value - The new value for the field
|
||||
*/
|
||||
const handleFieldChange = useCallback(
|
||||
<K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => {
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
[field]: value,
|
||||
}
|
||||
const handleFieldChange = async <K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => {
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
[field]: value,
|
||||
}
|
||||
|
||||
const protoConfig = convertApiConfigurationToProto(updatedConfig)
|
||||
ModelsServiceClient.updateApiConfigurationProto(
|
||||
UpdateApiConfigurationRequest.create({
|
||||
apiConfiguration: protoConfig,
|
||||
}),
|
||||
).catch((error) => {
|
||||
console.error(`Failed to update API configuration field ${field}:`, error)
|
||||
})
|
||||
},
|
||||
[apiConfiguration],
|
||||
)
|
||||
const protoConfig = convertApiConfigurationToProto(updatedConfig)
|
||||
await ModelsServiceClient.updateApiConfigurationProto(
|
||||
UpdateApiConfigurationRequest.create({
|
||||
apiConfiguration: protoConfig,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates multiple fields in the API configuration at once.
|
||||
@@ -45,24 +42,69 @@ export const useApiConfigurationHandlers = () => {
|
||||
*
|
||||
* @param updates - An object containing the fields to update and their new values
|
||||
*/
|
||||
const handleFieldsChange = useCallback(
|
||||
(updates: Partial<ApiConfiguration>) => {
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
...updates,
|
||||
}
|
||||
const handleFieldsChange = async (updates: Partial<ApiConfiguration>) => {
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
...updates,
|
||||
}
|
||||
|
||||
const protoConfig = convertApiConfigurationToProto(updatedConfig)
|
||||
ModelsServiceClient.updateApiConfigurationProto(
|
||||
UpdateApiConfigurationRequest.create({
|
||||
apiConfiguration: protoConfig,
|
||||
}),
|
||||
).catch((error) => {
|
||||
console.error("Failed to update API configuration fields:", error)
|
||||
const protoConfig = convertApiConfigurationToProto(updatedConfig)
|
||||
await ModelsServiceClient.updateApiConfigurationProto(
|
||||
UpdateApiConfigurationRequest.create({
|
||||
apiConfiguration: protoConfig,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const handleModeFieldChange = async <PlanK extends keyof ApiConfiguration, ActK extends keyof ApiConfiguration>(
|
||||
fieldPair: { plan: PlanK; act: ActK },
|
||||
value: ApiConfiguration[PlanK] & ApiConfiguration[ActK], // Intersection ensures value is compatible with both field types
|
||||
currentMode: Mode,
|
||||
) => {
|
||||
if (planActSeparateModelsSetting) {
|
||||
const targetField = fieldPair[currentMode]
|
||||
await handleFieldChange(targetField, value)
|
||||
} else {
|
||||
await handleFieldsChange({
|
||||
[fieldPair.plan]: value,
|
||||
[fieldPair.act]: value,
|
||||
})
|
||||
},
|
||||
[apiConfiguration],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return { handleFieldChange, handleFieldsChange, uriScheme, apiConfiguration }
|
||||
/**
|
||||
* Updates multiple mode-specific fields in a single atomic operation.
|
||||
*
|
||||
* This prevents race conditions that can occur when making multiple separate
|
||||
* handleModeFieldChange calls in rapid succession.
|
||||
*
|
||||
* @param fieldPairs - Object mapping keys to plan/act field pairs
|
||||
* @param values - Object with values for each key
|
||||
* @param currentMode - The current mode being targeted
|
||||
*/
|
||||
const handleModeFieldsChange = async <T extends Record<string, any>>(
|
||||
fieldPairs: { [K in keyof T]: { plan: keyof ApiConfiguration; act: keyof ApiConfiguration } },
|
||||
values: T,
|
||||
currentMode: Mode,
|
||||
) => {
|
||||
if (planActSeparateModelsSetting) {
|
||||
// Update only the current mode's fields
|
||||
const updates: Partial<ApiConfiguration> = {}
|
||||
Object.entries(fieldPairs).forEach(([key, { plan, act }]) => {
|
||||
const targetField = currentMode === "plan" ? plan : act
|
||||
updates[targetField] = values[key]
|
||||
})
|
||||
await handleFieldsChange(updates)
|
||||
} else {
|
||||
// Update both modes' fields
|
||||
const updates: Partial<ApiConfiguration> = {}
|
||||
Object.entries(fieldPairs).forEach(([key, { plan, act }]) => {
|
||||
updates[plan] = values[key]
|
||||
updates[act] = values[key]
|
||||
})
|
||||
await handleFieldsChange(updates)
|
||||
}
|
||||
}
|
||||
|
||||
return { handleFieldChange, handleFieldsChange, handleModeFieldChange, handleModeFieldsChange }
|
||||
}
|
||||
|
||||
@@ -1,19 +1,37 @@
|
||||
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useState, memo } from "react"
|
||||
import { useEffect, useState, memo } from "react"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
import { validateApiConfiguration } from "@/utils/validate"
|
||||
import ApiOptions from "@/components/settings/ApiOptions"
|
||||
import ClineLogoWhite from "@/assets/ClineLogoWhite"
|
||||
import { AccountServiceClient } from "@/services/grpc-client"
|
||||
import { EmptyRequest } from "@shared/proto/common"
|
||||
import { AccountServiceClient, StateServiceClient } from "@/services/grpc-client"
|
||||
import { EmptyRequest, BooleanRequest } from "@shared/proto/common"
|
||||
|
||||
const WelcomeView = memo(() => {
|
||||
const { apiConfiguration, chatSettings } = useExtensionState()
|
||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
||||
const [showApiOptions, setShowApiOptions] = useState(false)
|
||||
|
||||
const disableLetsGoButton = apiErrorMessage != null
|
||||
|
||||
const handleLogin = () => {
|
||||
AccountServiceClient.accountLoginClicked(EmptyRequest.create()).catch((err) =>
|
||||
console.error("Failed to get login URL:", err),
|
||||
)
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await StateServiceClient.setWelcomeViewCompleted(BooleanRequest.create({ value: true }))
|
||||
} catch (error) {
|
||||
console.error("Failed to update API configuration or complete welcome view:", error)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setApiErrorMessage(validateApiConfiguration(chatSettings.mode, apiConfiguration))
|
||||
}, [apiConfiguration, chatSettings.mode])
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 p-0 flex flex-col">
|
||||
<div className="h-full px-5 overflow-auto">
|
||||
@@ -49,7 +67,16 @@ const WelcomeView = memo(() => {
|
||||
</VSCodeButton>
|
||||
)}
|
||||
|
||||
<div className="mt-4.5">{showApiOptions && <ApiOptions showModelOptions={false} showSubmitButton={true} />}</div>
|
||||
<div className="mt-4.5">
|
||||
{showApiOptions && (
|
||||
<div>
|
||||
<ApiOptions showModelOptions={false} currentMode={chatSettings.mode} />
|
||||
<VSCodeButton onClick={handleSubmit} disabled={disableLetsGoButton} className="mt-0.75">
|
||||
Let's go!
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import { ApiConfiguration, openRouterDefaultModelId, ModelInfo } from "@shared/api"
|
||||
import { getModeSpecificFields } from "@/components/settings/utils/providerUtils"
|
||||
import { Mode } from "@shared/ChatSettings"
|
||||
|
||||
export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): string | undefined {
|
||||
export function validateApiConfiguration(currentMode: Mode, apiConfiguration?: ApiConfiguration): string | undefined {
|
||||
if (apiConfiguration) {
|
||||
switch (apiConfiguration.apiProvider) {
|
||||
const {
|
||||
apiProvider,
|
||||
openAiModelId,
|
||||
requestyModelId,
|
||||
fireworksModelId,
|
||||
togetherModelId,
|
||||
ollamaModelId,
|
||||
lmStudioModelId,
|
||||
vsCodeLmModelSelector,
|
||||
} = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
|
||||
switch (apiProvider) {
|
||||
case "anthropic":
|
||||
if (!apiConfiguration.apiKey) {
|
||||
return "You must provide a valid API key or choose a different provider."
|
||||
@@ -64,37 +77,37 @@ export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): s
|
||||
}
|
||||
break
|
||||
case "openai":
|
||||
if (!apiConfiguration.openAiBaseUrl || !apiConfiguration.openAiApiKey || !apiConfiguration.openAiModelId) {
|
||||
if (!apiConfiguration.openAiBaseUrl || !apiConfiguration.openAiApiKey || !openAiModelId) {
|
||||
return "You must provide a valid base URL, API key, and model ID."
|
||||
}
|
||||
break
|
||||
case "requesty":
|
||||
if (!apiConfiguration.requestyApiKey || !apiConfiguration.requestyModelId) {
|
||||
if (!apiConfiguration.requestyApiKey || !requestyModelId) {
|
||||
return "You must provide a valid API key or choose a different provider."
|
||||
}
|
||||
break
|
||||
case "fireworks":
|
||||
if (!apiConfiguration.fireworksApiKey || !apiConfiguration.fireworksModelId) {
|
||||
if (!apiConfiguration.fireworksApiKey || !fireworksModelId) {
|
||||
return "You must provide a valid API key or choose a different provider."
|
||||
}
|
||||
break
|
||||
case "together":
|
||||
if (!apiConfiguration.togetherApiKey || !apiConfiguration.togetherModelId) {
|
||||
if (!apiConfiguration.togetherApiKey || !togetherModelId) {
|
||||
return "You must provide a valid API key or choose a different provider."
|
||||
}
|
||||
break
|
||||
case "ollama":
|
||||
if (!apiConfiguration.ollamaModelId) {
|
||||
if (!ollamaModelId) {
|
||||
return "You must provide a valid model ID."
|
||||
}
|
||||
break
|
||||
case "lmstudio":
|
||||
if (!apiConfiguration.lmStudioModelId) {
|
||||
if (!lmStudioModelId) {
|
||||
return "You must provide a valid model ID."
|
||||
}
|
||||
break
|
||||
case "vscode-lm":
|
||||
if (!apiConfiguration.vsCodeLmModelSelector) {
|
||||
if (!vsCodeLmModelSelector) {
|
||||
return "You must provide a valid model selector."
|
||||
}
|
||||
break
|
||||
@@ -138,14 +151,16 @@ export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): s
|
||||
}
|
||||
|
||||
export function validateModelId(
|
||||
currentMode: Mode,
|
||||
apiConfiguration?: ApiConfiguration,
|
||||
openRouterModels?: Record<string, ModelInfo>,
|
||||
): string | undefined {
|
||||
if (apiConfiguration) {
|
||||
switch (apiConfiguration.apiProvider) {
|
||||
const { apiProvider, openRouterModelId } = getModeSpecificFields(apiConfiguration, currentMode)
|
||||
switch (apiProvider) {
|
||||
case "openrouter":
|
||||
case "cline":
|
||||
const modelId = apiConfiguration.openRouterModelId || openRouterDefaultModelId // in case the user hasn't changed the model id, it will be undefined by default
|
||||
const modelId = openRouterModelId || openRouterDefaultModelId // in case the user hasn't changed the model id, it will be undefined by default
|
||||
if (!modelId) {
|
||||
return "You must provide a model ID."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user