Introduce the ability to cycle between alternative inline assists (#18098)
Release Notes: - Added a new `assistant.inline_alternatives` setting to configure additional models that will be used to perform inline assists in parallel. --------- Co-authored-by: Nathan <nathan@zed.dev> Co-authored-by: Roy <roy@anthropic.com> Co-authored-by: Adam <wolffiex@anthropic.com>
This commit is contained in:
parent
ae34872f73
commit
15b4130fa5
8 changed files with 642 additions and 178 deletions
|
@ -520,6 +520,13 @@
|
||||||
"alt-enter": "editor::Newline"
|
"alt-enter": "editor::Newline"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"context": "PromptEditor",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-[": "assistant::CyclePreviousInlineAssist",
|
||||||
|
"ctrl-]": "assistant::CycleNextInlineAssist"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"context": "ProjectSearchBar && !in_replace",
|
"context": "ProjectSearchBar && !in_replace",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
|
|
@ -527,6 +527,13 @@
|
||||||
"ctrl-enter": "assistant::InlineAssist"
|
"ctrl-enter": "assistant::InlineAssist"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"context": "PromptEditor",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-[": "assistant::CyclePreviousInlineAssist",
|
||||||
|
"ctrl-]": "assistant::CycleNextInlineAssist"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"context": "ProjectSearchBar && !in_replace",
|
"context": "ProjectSearchBar && !in_replace",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
|
|
@ -69,6 +69,8 @@ actions!(
|
||||||
ConfirmCommand,
|
ConfirmCommand,
|
||||||
NewContext,
|
NewContext,
|
||||||
ToggleModelSelector,
|
ToggleModelSelector,
|
||||||
|
CycleNextInlineAssist,
|
||||||
|
CyclePreviousInlineAssist
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -359,8 +361,19 @@ fn update_active_language_model_from_settings(cx: &mut AppContext) {
|
||||||
let settings = AssistantSettings::get_global(cx);
|
let settings = AssistantSettings::get_global(cx);
|
||||||
let provider_name = LanguageModelProviderId::from(settings.default_model.provider.clone());
|
let provider_name = LanguageModelProviderId::from(settings.default_model.provider.clone());
|
||||||
let model_id = LanguageModelId::from(settings.default_model.model.clone());
|
let model_id = LanguageModelId::from(settings.default_model.model.clone());
|
||||||
|
let inline_alternatives = settings
|
||||||
|
.inline_alternatives
|
||||||
|
.iter()
|
||||||
|
.map(|alternative| {
|
||||||
|
(
|
||||||
|
LanguageModelProviderId::from(alternative.provider.clone()),
|
||||||
|
LanguageModelId::from(alternative.model.clone()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
|
LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
|
||||||
registry.select_active_model(&provider_name, &model_id, cx);
|
registry.select_active_model(&provider_name, &model_id, cx);
|
||||||
|
registry.select_inline_alternative_models(inline_alternatives, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ pub struct AssistantSettings {
|
||||||
pub default_width: Pixels,
|
pub default_width: Pixels,
|
||||||
pub default_height: Pixels,
|
pub default_height: Pixels,
|
||||||
pub default_model: LanguageModelSelection,
|
pub default_model: LanguageModelSelection,
|
||||||
|
pub inline_alternatives: Vec<LanguageModelSelection>,
|
||||||
pub using_outdated_settings_version: bool,
|
pub using_outdated_settings_version: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,6 +237,7 @@ impl AssistantSettingsContent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
inline_alternatives: None,
|
||||||
},
|
},
|
||||||
VersionedAssistantSettingsContent::V2(settings) => settings.clone(),
|
VersionedAssistantSettingsContent::V2(settings) => settings.clone(),
|
||||||
},
|
},
|
||||||
|
@ -254,6 +256,7 @@ impl AssistantSettingsContent {
|
||||||
.id()
|
.id()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
}),
|
}),
|
||||||
|
inline_alternatives: None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -369,6 +372,7 @@ impl Default for VersionedAssistantSettingsContent {
|
||||||
default_width: None,
|
default_width: None,
|
||||||
default_height: None,
|
default_height: None,
|
||||||
default_model: None,
|
default_model: None,
|
||||||
|
inline_alternatives: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,6 +401,8 @@ pub struct AssistantSettingsContentV2 {
|
||||||
default_height: Option<f32>,
|
default_height: Option<f32>,
|
||||||
/// The default model to use when creating new contexts.
|
/// The default model to use when creating new contexts.
|
||||||
default_model: Option<LanguageModelSelection>,
|
default_model: Option<LanguageModelSelection>,
|
||||||
|
/// Additional models with which to generate alternatives when performing inline assists.
|
||||||
|
inline_alternatives: Option<Vec<LanguageModelSelection>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||||
|
@ -517,10 +523,8 @@ impl Settings for AssistantSettings {
|
||||||
&mut settings.default_height,
|
&mut settings.default_height,
|
||||||
value.default_height.map(Into::into),
|
value.default_height.map(Into::into),
|
||||||
);
|
);
|
||||||
merge(
|
merge(&mut settings.default_model, value.default_model);
|
||||||
&mut settings.default_model,
|
merge(&mut settings.inline_alternatives, value.inline_alternatives);
|
||||||
value.default_model.map(Into::into),
|
|
||||||
);
|
|
||||||
// merge(&mut settings.infer_context, value.infer_context); TODO re-enable this once we ship context inference
|
// merge(&mut settings.infer_context, value.infer_context); TODO re-enable this once we ship context inference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,6 +578,7 @@ mod tests {
|
||||||
provider: "test-provider".into(),
|
provider: "test-provider".into(),
|
||||||
model: "gpt-99".into(),
|
model: "gpt-99".into(),
|
||||||
}),
|
}),
|
||||||
|
inline_alternatives: None,
|
||||||
enabled: None,
|
enabled: None,
|
||||||
button: None,
|
button: None,
|
||||||
dock: None,
|
dock: None,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -76,6 +76,7 @@ impl Global for GlobalLanguageModelRegistry {}
|
||||||
pub struct LanguageModelRegistry {
|
pub struct LanguageModelRegistry {
|
||||||
active_model: Option<ActiveModel>,
|
active_model: Option<ActiveModel>,
|
||||||
providers: BTreeMap<LanguageModelProviderId, Arc<dyn LanguageModelProvider>>,
|
providers: BTreeMap<LanguageModelProviderId, Arc<dyn LanguageModelProvider>>,
|
||||||
|
inline_alternatives: Vec<Arc<dyn LanguageModel>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ActiveModel {
|
pub struct ActiveModel {
|
||||||
|
@ -229,6 +230,37 @@ impl LanguageModelRegistry {
|
||||||
pub fn active_model(&self) -> Option<Arc<dyn LanguageModel>> {
|
pub fn active_model(&self) -> Option<Arc<dyn LanguageModel>> {
|
||||||
self.active_model.as_ref()?.model.clone()
|
self.active_model.as_ref()?.model.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects and sets the inline alternatives for language models based on
|
||||||
|
/// provider name and id.
|
||||||
|
pub fn select_inline_alternative_models(
|
||||||
|
&mut self,
|
||||||
|
alternatives: impl IntoIterator<Item = (LanguageModelProviderId, LanguageModelId)>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
let mut selected_alternatives = Vec::new();
|
||||||
|
|
||||||
|
for (provider_id, model_id) in alternatives {
|
||||||
|
if let Some(provider) = self.providers.get(&provider_id) {
|
||||||
|
if let Some(model) = provider
|
||||||
|
.provided_models(cx)
|
||||||
|
.iter()
|
||||||
|
.find(|m| m.id() == model_id)
|
||||||
|
{
|
||||||
|
selected_alternatives.push(model.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.inline_alternatives = selected_alternatives;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The models to use for inline assists. Returns the union of the active
|
||||||
|
/// model and all inline alternatives. When there are multiple models, the
|
||||||
|
/// user will be able to cycle through results.
|
||||||
|
pub fn inline_alternative_models(&self) -> &[Arc<dyn LanguageModel>] {
|
||||||
|
&self.inline_alternatives
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1106,6 +1106,26 @@ impl MultiBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn forget_transaction(
|
||||||
|
&mut self,
|
||||||
|
transaction_id: TransactionId,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
if let Some(buffer) = self.as_singleton() {
|
||||||
|
buffer.update(cx, |buffer, _| {
|
||||||
|
buffer.forget_transaction(transaction_id);
|
||||||
|
});
|
||||||
|
} else if let Some(transaction) = self.history.forget(transaction_id) {
|
||||||
|
for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
|
||||||
|
if let Some(state) = self.buffers.borrow_mut().get_mut(&buffer_id) {
|
||||||
|
state.buffer.update(cx, |buffer, _| {
|
||||||
|
buffer.forget_transaction(buffer_transaction_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stream_excerpts_with_context_lines(
|
pub fn stream_excerpts_with_context_lines(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: Model<Buffer>,
|
buffer: Model<Buffer>,
|
||||||
|
|
|
@ -20,6 +20,7 @@ To further customize providers, you can use `settings.json` to do that as follow
|
||||||
- [Configuring endpoints](#custom-endpoint)
|
- [Configuring endpoints](#custom-endpoint)
|
||||||
- [Configuring timeouts](#provider-timeout)
|
- [Configuring timeouts](#provider-timeout)
|
||||||
- [Configuring default model](#default-model)
|
- [Configuring default model](#default-model)
|
||||||
|
- [Configuring alternative models for inline assists](#alternative-assists)
|
||||||
|
|
||||||
### Zed AI {#zed-ai}
|
### Zed AI {#zed-ai}
|
||||||
|
|
||||||
|
@ -264,6 +265,31 @@ You can also manually edit the `default_model` object in your settings:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Configuring alternative models for inline assists {#alternative-assists}
|
||||||
|
|
||||||
|
You can configure additional models that will be used to perform inline assists in parallel. When you do this,
|
||||||
|
the inline assist UI will surface controls to cycle between the alternatives generated by each model. The models
|
||||||
|
you specify here are always used in _addition_ to your default model. For example, the following configuration
|
||||||
|
will generate two outputs for every assist. One with Claude 3.5 Sonnet, and one with GPT-4o.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"assistant": {
|
||||||
|
"default_model": {
|
||||||
|
"provider": "zed.dev",
|
||||||
|
"model": "claude-3-5-sonnet"
|
||||||
|
},
|
||||||
|
"inline_alternatives": [
|
||||||
|
{
|
||||||
|
"provider": "zed.dev",
|
||||||
|
"model": "gpt-4o"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### Common Panel Settings
|
#### Common Panel Settings
|
||||||
|
|
||||||
| key | type | default | description |
|
| key | type | default | description |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue