Render messages as early as possible to show progress (#11569)
This shows "Researching..." as placeholder text as early as possible so that the user can see the model is working on reading/researching/etc. This also adds on an `Option<Value>` to the `render_running` function so that tools can hopefully render based on partially completed JSON (still to come). Release Notes: - N/A
This commit is contained in:
parent
dbebb40956
commit
689e4aef2f
6 changed files with 46 additions and 15 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -423,6 +423,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
"sum_tree",
|
"sum_tree",
|
||||||
|
"ui",
|
||||||
"unindent",
|
"unindent",
|
||||||
"util",
|
"util",
|
||||||
]
|
]
|
||||||
|
|
|
@ -16,7 +16,8 @@ use crate::{
|
||||||
use ::ui::{div, prelude::*, Color, Tooltip, ViewContext};
|
use ::ui::{div, prelude::*, Color, Tooltip, ViewContext};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use assistant_tooling::{
|
use assistant_tooling::{
|
||||||
AttachmentRegistry, ProjectContext, ToolFunctionCall, ToolRegistry, UserAttachment,
|
tool_running_placeholder, AttachmentRegistry, ProjectContext, ToolFunctionCall, ToolRegistry,
|
||||||
|
UserAttachment,
|
||||||
};
|
};
|
||||||
use client::{proto, Client, UserStore};
|
use client::{proto, Client, UserStore};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
@ -864,6 +865,10 @@ impl AssistantChat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if message_elements.is_empty() {
|
||||||
|
message_elements.push(tool_running_placeholder());
|
||||||
|
}
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.when(is_first, |this| this.pt(padding))
|
.when(is_first, |this| this.pt(padding))
|
||||||
.child(
|
.child(
|
||||||
|
|
|
@ -6,6 +6,7 @@ use project::ProjectPath;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use semantic_index::{ProjectIndex, Status};
|
use semantic_index::{ProjectIndex, Status};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use serde_json::Value;
|
||||||
use std::{fmt::Write as _, ops::Range};
|
use std::{fmt::Write as _, ops::Range};
|
||||||
use ui::{div, prelude::*, CollapsibleContainer, Color, Icon, IconName, Label, WindowContext};
|
use ui::{div, prelude::*, CollapsibleContainer, Color, Icon, IconName, Label, WindowContext};
|
||||||
|
|
||||||
|
@ -202,8 +203,14 @@ impl LanguageModelTool for ProjectIndexTool {
|
||||||
cx.new_view(|_cx| ProjectIndexView::new(input, output))
|
cx.new_view(|_cx| ProjectIndexView::new(input, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_running(_: &mut WindowContext) -> impl IntoElement {
|
fn render_running(arguments: &Option<Value>, _: &mut WindowContext) -> impl IntoElement {
|
||||||
CollapsibleContainer::new(ElementId::Name(nanoid::nanoid!().into()), false)
|
let text: String = arguments
|
||||||
.start_slot("Searching code base")
|
.as_ref()
|
||||||
|
.and_then(|arguments| arguments.get("query"))
|
||||||
|
.and_then(|query| query.as_str())
|
||||||
|
.map(|query| format!("Searching for: {}", query))
|
||||||
|
.unwrap_or_else(|| "Preparing search...".to_string());
|
||||||
|
|
||||||
|
CollapsibleContainer::new(ElementId::Name(nanoid::nanoid!().into()), false).start_slot(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ schemars.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
sum_tree.workspace = true
|
sum_tree.workspace = true
|
||||||
|
ui.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -5,5 +5,6 @@ mod tool_registry;
|
||||||
pub use attachment_registry::{AttachmentRegistry, LanguageModelAttachment, UserAttachment};
|
pub use attachment_registry::{AttachmentRegistry, LanguageModelAttachment, UserAttachment};
|
||||||
pub use project_context::ProjectContext;
|
pub use project_context::ProjectContext;
|
||||||
pub use tool_registry::{
|
pub use tool_registry::{
|
||||||
LanguageModelTool, ToolFunctionCall, ToolFunctionDefinition, ToolOutput, ToolRegistry,
|
tool_running_placeholder, LanguageModelTool, ToolFunctionCall, ToolFunctionDefinition,
|
||||||
|
ToolOutput, ToolRegistry,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use schemars::{schema::RootSchema, schema_for, JsonSchema};
|
use schemars::{schema::RootSchema, schema_for, JsonSchema};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use serde_json::Value;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
@ -78,17 +79,22 @@ pub trait LanguageModelTool {
|
||||||
/// Executes the tool with the given input.
|
/// Executes the tool with the given input.
|
||||||
fn execute(&self, input: &Self::Input, cx: &mut WindowContext) -> Task<Result<Self::Output>>;
|
fn execute(&self, input: &Self::Input, cx: &mut WindowContext) -> Task<Result<Self::Output>>;
|
||||||
|
|
||||||
|
/// A view of the output of running the tool, for displaying to the user.
|
||||||
fn output_view(
|
fn output_view(
|
||||||
input: Self::Input,
|
input: Self::Input,
|
||||||
output: Result<Self::Output>,
|
output: Result<Self::Output>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> View<Self::View>;
|
) -> View<Self::View>;
|
||||||
|
|
||||||
fn render_running(_cx: &mut WindowContext) -> impl IntoElement {
|
fn render_running(_arguments: &Option<Value>, _cx: &mut WindowContext) -> impl IntoElement {
|
||||||
div()
|
tool_running_placeholder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tool_running_placeholder() -> AnyElement {
|
||||||
|
ui::Label::new("Researching...").into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ToolOutput: Sized {
|
pub trait ToolOutput: Sized {
|
||||||
fn generate(&self, project: &mut ProjectContext, cx: &mut WindowContext) -> String;
|
fn generate(&self, project: &mut ProjectContext, cx: &mut WindowContext) -> String;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +103,7 @@ struct RegisteredTool {
|
||||||
enabled: AtomicBool,
|
enabled: AtomicBool,
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
call: Box<dyn Fn(&ToolFunctionCall, &mut WindowContext) -> Task<Result<ToolFunctionCall>>>,
|
call: Box<dyn Fn(&ToolFunctionCall, &mut WindowContext) -> Task<Result<ToolFunctionCall>>>,
|
||||||
render_running: fn(&mut WindowContext) -> gpui::AnyElement,
|
render_running: fn(&ToolFunctionCall, &mut WindowContext) -> gpui::AnyElement,
|
||||||
definition: ToolFunctionDefinition,
|
definition: ToolFunctionDefinition,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,11 +150,15 @@ impl ToolRegistry {
|
||||||
.p_2()
|
.p_2()
|
||||||
.child(result.into_any_element(&tool_call.name))
|
.child(result.into_any_element(&tool_call.name))
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
None => self
|
None => {
|
||||||
.registered_tools
|
let tool = self.registered_tools.get(&tool_call.name);
|
||||||
.get(&tool_call.name)
|
|
||||||
.map(|tool| (tool.render_running)(cx))
|
if let Some(tool) = tool {
|
||||||
.unwrap_or_else(|| div().into_any_element()),
|
(tool.render_running)(&tool_call, cx)
|
||||||
|
} else {
|
||||||
|
tool_running_placeholder()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,8 +215,14 @@ impl ToolRegistry {
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
||||||
fn render_running<T: LanguageModelTool>(cx: &mut WindowContext) -> AnyElement {
|
fn render_running<T: LanguageModelTool>(
|
||||||
T::render_running(cx).into_any_element()
|
tool_call: &ToolFunctionCall,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> AnyElement {
|
||||||
|
// Attempt to parse the string arguments that are JSON as a JSON value
|
||||||
|
let maybe_arguments = serde_json::to_value(tool_call.arguments.clone()).ok();
|
||||||
|
|
||||||
|
T::render_running(&maybe_arguments, cx).into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate<T: LanguageModelTool>(
|
fn generate<T: LanguageModelTool>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue