assistant_settings.rs

  1use ai::providers::open_ai::{
  2    AzureOpenAiApiVersion, OpenAiCompletionProviderKind, OPEN_AI_API_URL,
  3};
  4use anyhow::anyhow;
  5use gpui::Pixels;
  6use schemars::JsonSchema;
  7use serde::{Deserialize, Serialize};
  8use settings::Settings;
  9
 10#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
 11#[serde(rename_all = "snake_case")]
 12pub enum OpenAiModel {
 13    #[serde(rename = "gpt-3.5-turbo-0613")]
 14    ThreePointFiveTurbo,
 15    #[serde(rename = "gpt-4-0613")]
 16    Four,
 17    #[serde(rename = "gpt-4-1106-preview")]
 18    FourTurbo,
 19}
 20
 21impl OpenAiModel {
 22    pub fn full_name(&self) -> &'static str {
 23        match self {
 24            Self::ThreePointFiveTurbo => "gpt-3.5-turbo-0613",
 25            Self::Four => "gpt-4-0613",
 26            Self::FourTurbo => "gpt-4-1106-preview",
 27        }
 28    }
 29
 30    pub fn short_name(&self) -> &'static str {
 31        match self {
 32            Self::ThreePointFiveTurbo => "gpt-3.5-turbo",
 33            Self::Four => "gpt-4",
 34            Self::FourTurbo => "gpt-4-turbo",
 35        }
 36    }
 37
 38    pub fn cycle(&self) -> Self {
 39        match self {
 40            Self::ThreePointFiveTurbo => Self::Four,
 41            Self::Four => Self::FourTurbo,
 42            Self::FourTurbo => Self::ThreePointFiveTurbo,
 43        }
 44    }
 45}
 46
 47#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
 48#[serde(rename_all = "snake_case")]
 49pub enum AssistantDockPosition {
 50    Left,
 51    Right,
 52    Bottom,
 53}
 54
 55#[derive(Debug, Deserialize)]
 56pub struct AssistantSettings {
 57    /// Whether to show the assistant panel button in the status bar.
 58    pub button: bool,
 59    /// Where to dock the assistant.
 60    pub dock: AssistantDockPosition,
 61    /// Default width in pixels when the assistant is docked to the left or right.
 62    pub default_width: Pixels,
 63    /// Default height in pixels when the assistant is docked to the bottom.
 64    pub default_height: Pixels,
 65    /// The default OpenAI model to use when starting new conversations.
 66    #[deprecated = "Please use `provider.default_model` instead."]
 67    pub default_open_ai_model: OpenAiModel,
 68    /// OpenAI API base URL to use when starting new conversations.
 69    #[deprecated = "Please use `provider.api_url` instead."]
 70    pub openai_api_url: String,
 71    /// The settings for the AI provider.
 72    pub provider: AiProviderSettings,
 73}
 74
 75impl AssistantSettings {
 76    pub fn provider_kind(&self) -> anyhow::Result<OpenAiCompletionProviderKind> {
 77        match &self.provider {
 78            AiProviderSettings::OpenAi(_) => Ok(OpenAiCompletionProviderKind::OpenAi),
 79            AiProviderSettings::AzureOpenAi(settings) => {
 80                let deployment_id = settings
 81                    .deployment_id
 82                    .clone()
 83                    .ok_or_else(|| anyhow!("no Azure OpenAI deployment ID"))?;
 84                let api_version = settings
 85                    .api_version
 86                    .ok_or_else(|| anyhow!("no Azure OpenAI API version"))?;
 87
 88                Ok(OpenAiCompletionProviderKind::AzureOpenAi {
 89                    deployment_id,
 90                    api_version,
 91                })
 92            }
 93        }
 94    }
 95
 96    pub fn provider_api_url(&self) -> anyhow::Result<String> {
 97        match &self.provider {
 98            AiProviderSettings::OpenAi(settings) => Ok(settings
 99                .api_url
100                .clone()
101                .unwrap_or_else(|| OPEN_AI_API_URL.to_string())),
102            AiProviderSettings::AzureOpenAi(settings) => settings
103                .api_url
104                .clone()
105                .ok_or_else(|| anyhow!("no Azure OpenAI API URL")),
106        }
107    }
108
109    pub fn provider_model(&self) -> anyhow::Result<OpenAiModel> {
110        match &self.provider {
111            AiProviderSettings::OpenAi(settings) => {
112                Ok(settings.default_model.unwrap_or(OpenAiModel::FourTurbo))
113            }
114            AiProviderSettings::AzureOpenAi(settings) => {
115                let deployment_id = settings
116                    .deployment_id
117                    .as_deref()
118                    .ok_or_else(|| anyhow!("no Azure OpenAI deployment ID"))?;
119
120                match deployment_id {
121                    // https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-preview
122                    "gpt-4" | "gpt-4-32k" => Ok(OpenAiModel::Four),
123                    // https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models#gpt-35
124                    "gpt-35-turbo" | "gpt-35-turbo-16k" | "gpt-35-turbo-instruct" => {
125                        Ok(OpenAiModel::ThreePointFiveTurbo)
126                    }
127                    _ => Err(anyhow!(
128                        "no matching OpenAI model found for deployment ID: '{deployment_id}'"
129                    )),
130                }
131            }
132        }
133    }
134
135    pub fn provider_model_name(&self) -> anyhow::Result<String> {
136        match &self.provider {
137            AiProviderSettings::OpenAi(settings) => Ok(settings
138                .default_model
139                .unwrap_or(OpenAiModel::FourTurbo)
140                .full_name()
141                .to_string()),
142            AiProviderSettings::AzureOpenAi(settings) => settings
143                .deployment_id
144                .clone()
145                .ok_or_else(|| anyhow!("no Azure OpenAI deployment ID")),
146        }
147    }
148}
149
150impl Settings for AssistantSettings {
151    const KEY: Option<&'static str> = Some("assistant");
152
153    type FileContent = AssistantSettingsContent;
154
155    fn load(
156        default_value: &Self::FileContent,
157        user_values: &[&Self::FileContent],
158        _: &mut gpui::AppContext,
159    ) -> anyhow::Result<Self> {
160        Self::load_via_json_merge(default_value, user_values)
161    }
162}
163
164/// Assistant panel settings
165#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
166pub struct AssistantSettingsContent {
167    /// Whether to show the assistant panel button in the status bar.
168    ///
169    /// Default: true
170    pub button: Option<bool>,
171    /// Where to dock the assistant.
172    ///
173    /// Default: right
174    pub dock: Option<AssistantDockPosition>,
175    /// Default width in pixels when the assistant is docked to the left or right.
176    ///
177    /// Default: 640
178    pub default_width: Option<f32>,
179    /// Default height in pixels when the assistant is docked to the bottom.
180    ///
181    /// Default: 320
182    pub default_height: Option<f32>,
183    /// Deprecated: Please use `provider.default_model` instead.
184    /// The default OpenAI model to use when starting new conversations.
185    ///
186    /// Default: gpt-4-1106-preview
187    #[deprecated = "Please use `provider.default_model` instead."]
188    pub default_open_ai_model: Option<OpenAiModel>,
189    /// Deprecated: Please use `provider.api_url` instead.
190    /// OpenAI API base URL to use when starting new conversations.
191    ///
192    /// Default: https://api.openai.com/v1
193    #[deprecated = "Please use `provider.api_url` instead."]
194    pub openai_api_url: Option<String>,
195    /// The settings for the AI provider.
196    #[serde(default)]
197    pub provider: AiProviderSettingsContent,
198}
199
200#[derive(Debug, Clone, Deserialize)]
201#[serde(tag = "type", rename_all = "snake_case")]
202pub enum AiProviderSettings {
203    /// The settings for the OpenAI provider.
204    #[serde(rename = "openai")]
205    OpenAi(OpenAiProviderSettings),
206    /// The settings for the Azure OpenAI provider.
207    #[serde(rename = "azure_openai")]
208    AzureOpenAi(AzureOpenAiProviderSettings),
209}
210
211/// The settings for the AI provider used by the Zed Assistant.
212#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
213#[serde(tag = "type", rename_all = "snake_case")]
214pub enum AiProviderSettingsContent {
215    /// The settings for the OpenAI provider.
216    #[serde(rename = "openai")]
217    OpenAi(OpenAiProviderSettingsContent),
218    /// The settings for the Azure OpenAI provider.
219    #[serde(rename = "azure_openai")]
220    AzureOpenAi(AzureOpenAiProviderSettingsContent),
221}
222
223impl Default for AiProviderSettingsContent {
224    fn default() -> Self {
225        Self::OpenAi(OpenAiProviderSettingsContent::default())
226    }
227}
228
229#[derive(Debug, Clone, Deserialize)]
230pub struct OpenAiProviderSettings {
231    /// The OpenAI API base URL to use when starting new conversations.
232    pub api_url: Option<String>,
233    /// The default OpenAI model to use when starting new conversations.
234    pub default_model: Option<OpenAiModel>,
235}
236
237#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
238pub struct OpenAiProviderSettingsContent {
239    /// The OpenAI API base URL to use when starting new conversations.
240    ///
241    /// Default: https://api.openai.com/v1
242    pub api_url: Option<String>,
243    /// The default OpenAI model to use when starting new conversations.
244    ///
245    /// Default: gpt-4-1106-preview
246    pub default_model: Option<OpenAiModel>,
247}
248
249#[derive(Debug, Clone, Deserialize)]
250pub struct AzureOpenAiProviderSettings {
251    /// The Azure OpenAI API base URL to use when starting new conversations.
252    pub api_url: Option<String>,
253    /// The Azure OpenAI API version.
254    pub api_version: Option<AzureOpenAiApiVersion>,
255    /// The Azure OpenAI API deployment ID.
256    pub deployment_id: Option<String>,
257}
258
259#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
260pub struct AzureOpenAiProviderSettingsContent {
261    /// The Azure OpenAI API base URL to use when starting new conversations.
262    pub api_url: Option<String>,
263    /// The Azure OpenAI API version.
264    pub api_version: Option<AzureOpenAiApiVersion>,
265    /// The Azure OpenAI deployment ID.
266    pub deployment_id: Option<String>,
267}