Don't send contents of large @mention-ed files (#38032)

<img width="598" height="311" alt="Screenshot 2025-09-11 at 9 39 12 PM"
src="https://github.com/user-attachments/assets/b526e648-37cf-4412-83a0-42037b9fc94d"
/>

This is for both ACP and the regular agent. Previously we would always
include the whole file, which can easily blow the context window on huge
files.

Release Notes:

- When `@mention`ing large files, the Agent Panel now send an outline of
the file instead of the whole thing.
This commit is contained in:
Richard Feldman
2025-09-11 22:18:42 -04:00
committed by GitHub
parent bdf44e55aa
commit 405d7d7476
5 changed files with 224 additions and 90 deletions
+10 -36
View File
@@ -6,7 +6,7 @@ use futures::future;
use futures::{FutureExt, future::Shared};
use gpui::{App, AppContext as _, ElementId, Entity, SharedString, Task};
use icons::IconName;
use language::{Buffer, ParseStatus};
use language::Buffer;
use language_model::{LanguageModelImage, LanguageModelRequestMessage, MessageContent};
use project::{Project, ProjectEntryId, ProjectPath, Worktree};
use prompt_store::{PromptStore, UserPromptId};
@@ -191,45 +191,19 @@ impl FileContextHandle {
let buffer = self.buffer.clone();
cx.spawn(async move |cx| {
// For large files, use outline instead of full content
if rope.len() > outline::AUTO_OUTLINE_SIZE {
// Wait until the buffer has been fully parsed, so we can read its outline
if let Ok(mut parse_status) =
buffer.read_with(cx, |buffer, _| buffer.parse_status())
{
while *parse_status.borrow() != ParseStatus::Idle {
parse_status.changed().await.log_err();
}
let buffer_content =
outline::get_buffer_content_or_outline(buffer.clone(), Some(&full_path), &cx)
.await
.unwrap_or_else(|_| outline::BufferContent {
text: rope.to_string(),
is_outline: false,
});
if let Ok(snapshot) = buffer.read_with(cx, |buffer, _| buffer.snapshot()) {
let items = snapshot
.outline(None)
.items
.into_iter()
.map(|item| item.to_point(&snapshot));
if let Ok(outline_text) =
outline::render_outline(items, None, 0, usize::MAX).await
{
let context = AgentContext::File(FileContext {
handle: self,
full_path,
text: outline_text.into(),
is_outline: true,
});
return Some((context, vec![buffer]));
}
}
}
}
// Fallback to full content if we couldn't build an outline
// (or didn't need to because the file was small enough)
let context = AgentContext::File(FileContext {
handle: self,
full_path,
text: rope.to_string().into(),
is_outline: false,
text: buffer_content.text.into(),
is_outline: buffer_content.is_outline,
});
Some((context, vec![buffer]))
})