agent2: Add custom UI for resource link content blocks (#36005)

Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <agus@zed.dev>
This commit is contained in:
Danilo Leal 2025-08-12 12:39:27 -03:00 committed by GitHub
parent d2162446d0
commit b105028c05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 192 additions and 114 deletions

View file

@ -299,6 +299,7 @@ impl Display for ToolCallStatus {
pub enum ContentBlock {
Empty,
Markdown { markdown: Entity<Markdown> },
ResourceLink { resource_link: acp::ResourceLink },
}
impl ContentBlock {
@ -330,8 +331,56 @@ impl ContentBlock {
language_registry: &Arc<LanguageRegistry>,
cx: &mut App,
) {
let new_content = match block {
if matches!(self, ContentBlock::Empty) {
if let acp::ContentBlock::ResourceLink(resource_link) = block {
*self = ContentBlock::ResourceLink { resource_link };
return;
}
}
let new_content = self.extract_content_from_block(block);
match self {
ContentBlock::Empty => {
*self = Self::create_markdown_block(new_content, language_registry, cx);
}
ContentBlock::Markdown { markdown } => {
markdown.update(cx, |markdown, cx| markdown.append(&new_content, cx));
}
ContentBlock::ResourceLink { resource_link } => {
let existing_content = Self::resource_link_to_content(&resource_link.uri);
let combined = format!("{}\n{}", existing_content, new_content);
*self = Self::create_markdown_block(combined, language_registry, cx);
}
}
}
fn resource_link_to_content(uri: &str) -> String {
if let Some(uri) = MentionUri::parse(&uri).log_err() {
uri.to_link()
} else {
uri.to_string().clone()
}
}
fn create_markdown_block(
content: String,
language_registry: &Arc<LanguageRegistry>,
cx: &mut App,
) -> ContentBlock {
ContentBlock::Markdown {
markdown: cx
.new(|cx| Markdown::new(content.into(), Some(language_registry.clone()), None, cx)),
}
}
fn extract_content_from_block(&self, block: acp::ContentBlock) -> String {
match block {
acp::ContentBlock::Text(text_content) => text_content.text.clone(),
acp::ContentBlock::ResourceLink(resource_link) => {
Self::resource_link_to_content(&resource_link.uri)
}
acp::ContentBlock::Resource(acp::EmbeddedResource {
resource:
acp::EmbeddedResourceResource::TextResourceContents(acp::TextResourceContents {
@ -339,35 +388,10 @@ impl ContentBlock {
..
}),
..
}) => {
if let Some(uri) = MentionUri::parse(&uri).log_err() {
uri.to_link()
} else {
uri.clone()
}
}
}) => Self::resource_link_to_content(&uri),
acp::ContentBlock::Image(_)
| acp::ContentBlock::Audio(_)
| acp::ContentBlock::Resource(acp::EmbeddedResource { .. })
| acp::ContentBlock::ResourceLink(_) => String::new(),
};
match self {
ContentBlock::Empty => {
*self = ContentBlock::Markdown {
markdown: cx.new(|cx| {
Markdown::new(
new_content.into(),
Some(language_registry.clone()),
None,
cx,
)
}),
};
}
ContentBlock::Markdown { markdown } => {
markdown.update(cx, |markdown, cx| markdown.append(&new_content, cx));
}
| acp::ContentBlock::Resource(_) => String::new(),
}
}
@ -375,6 +399,7 @@ impl ContentBlock {
match self {
ContentBlock::Empty => "",
ContentBlock::Markdown { markdown } => markdown.read(cx).source(),
ContentBlock::ResourceLink { resource_link } => &resource_link.uri,
}
}
@ -382,6 +407,14 @@ impl ContentBlock {
match self {
ContentBlock::Empty => None,
ContentBlock::Markdown { markdown } => Some(markdown),
ContentBlock::ResourceLink { .. } => None,
}
}
pub fn resource_link(&self) -> Option<&acp::ResourceLink> {
match self {
ContentBlock::ResourceLink { resource_link } => Some(resource_link),
_ => None,
}
}
}

View file

@ -19,7 +19,10 @@ impl MentionUri {
if let Some(fragment) = url.fragment() {
Ok(Self::Symbol(path.into(), fragment.into()))
} else {
Ok(Self::File(path.into()))
let file_path =
PathBuf::from(format!("{}{}", url.host_str().unwrap_or(""), path));
Ok(Self::File(file_path))
}
}
"zed" => {