#[cfg(test)]mod context_tests; use crate::{ prompts::PromptBuilder, slash_command::SlashCommandLine, MessageId, MessageStatus, WorkflowStep, WorkflowStepEdit, WorkflowStepResolution, WorkflowSuggestionGroup,};use anyhow::{anyhow, Context as _, Result};use assistant_slash_command::{ SlashCommandOutput, SlashCommandOutputSection, SlashCommandRegistry,};use assistant_tool::ToolRegistry;use client::{self, proto, telemetry::Telemetry};use clock::ReplicaId;use collections::{HashMap, HashSet};use feature_flags::{FeatureFlag, FeatureFlagAppExt};use fs::{Fs, RemoveOptions};use futures::{ future::{self, Shared}, FutureExt, StreamExt,};use gpui::{ AppContext, AsyncAppContext, Context as _, EventEmitter, Model, ModelContext, RenderImage, SharedString, Subscription, Task,}; use language::{AnchorRangeExt, Bias, Buffer, LanguageRegistry, OffsetRangeExt, Point, ToOffset};use language_model::{ LanguageModel, LanguageModelCacheConfiguration, LanguageModelCompletionEvent, LanguageModelImage, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, LanguageModelRequestTool, LanguageModelToolResult, LanguageModelToolUse, MessageContent, Role, StopReason,};use open_ai::Model as OpenAiModel;use paths::contexts_dir;use project::Project;use serde::{Deserialize, Serialize};use smallvec::SmallVec;use std::{ cmp::{self, max, Ordering}, fmt::Debug, iter, mem, ops::Range, path::{Path, PathBuf}, str::FromStr as _, sync::Arc, time::{Duration, Instant},};use telemetry_events::AssistantKind;use text::BufferSnapshot;use util::{post_inc, TryFutureExt};use uuid::Uuid; #[derive(Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]pub struct ContextId(String); impl ContextId { pub fn new() -> Self { Self(Uuid::new_v4().to_string()) } pub fn from_proto(id: String) -> Self { Self(id) } pub fn to_proto(&self) -> String { self.0.clone() }} #[derive(Clone, Debug)]pub enum ContextOperation { InsertMessage { anchor: MessageAnchor, metadata: MessageMetadata, version: clock::Global, }, UpdateMessage { message_id: MessageId, metadata: MessageMetadata, version: clock::Global, }, UpdateSummary { summary: ContextSummary, version: clock::Global, }, SlashCommandFinished { id: SlashCommandId, output_range: Range<language::Anchor>, sections: Vec<SlashCommandOutputSection<language::Anchor>>, version: clock::Global, }, BufferOperation(language::Operation),} impl ContextOperation { pub fn from_proto(op: proto::ContextOperation) -> Result<Self> { match op.variant.context("invalid variant")? { proto::context_operation::Variant::InsertMessage(insert) => { let message = insert.message.context("invalid message")?; let id = MessageId(language::proto::deserialize_timestamp( message.id.context("invalid id")?, )); Ok(Self::InsertMessage { anchor: MessageAnchor { id, start: language::proto::deserialize_anchor( message.start.context("invalid anchor")?, ) .context("invalid anchor")?, }, metadata: MessageMetadata { role: Role::from_proto(message.role), status: MessageStatus::from_proto( message.status.context("invalid status")?, ), timestamp: id.0, cache: None, }, version: language::proto::deserialize_version(&insert.version), }) } proto::context_operation::Variant::UpdateMessage(update) => Ok(Self::UpdateMessage { message_id: MessageId(language::proto::deserialize_timestamp( update.message_id.context("invalid message id")?, )), metadata: MessageMetadata { role: Role::from_proto(update.role), status: MessageStatus::from_proto(update.status.context("invalid status")?), timestamp: language::proto::deserialize_timestamp( update.timestamp.context("invalid timestamp")?, ), cache: None, }, version: language::proto::deserialize_version(&update.version), }), proto::context_operation::Variant::UpdateSummary(update) => Ok(Self::UpdateSummary { summary: ContextSummary { text: update.summary, done: update.done, timestamp: language::proto::deserialize_timestamp( update.timestamp.context("invalid timestamp")?, ), }, version: language::proto::deserialize_version(&update.version), }), proto::context_operation::Variant::SlashCommandFinished(finished) => { Ok(Self::SlashCommandFinished { id: SlashCommandId(language::proto::deserialize_timestamp( finished.id.context("invalid id")?, )), output_range: language::proto::deserialize_anchor_range( finished.output_range.context("invalid range")?, )?, sections: finished .sections .into_iter() .map(|section| { Ok(SlashCommandOutputSection { range: language::proto::deserialize_anchor_range( section.range.context("invalid range")?, )?, icon: section.icon_name.parse()?, label: section.label.into(), }) }) .collect::<Result<Vec<_>>>()?, version: language::proto::deserialize_version(&finished.version), }) } proto::context_operation::Variant::BufferOperation(op) => Ok(Self::BufferOperation( language::proto::deserialize_operation( op.operation.context("invalid buffer operation")?, )?, )), } } pub fn to_proto(&self) -> proto::ContextOperation { match self { Self::InsertMessage { anchor, metadata, version, } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::InsertMessage( proto::context_operation::InsertMessage { message: Some(proto::ContextMessage { id: Some(language::proto::serialize_timestamp(anchor.id.0)), start: Some(language::proto::serialize_anchor(&anchor.start)), role: metadata.role.to_proto() as i32, status: Some(metadata.status.to_proto()), }), version: language::proto::serialize_version(version), }, )), }, Self::UpdateMessage { message_id, metadata, version, } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::UpdateMessage( proto::context_operation::UpdateMessage { message_id: Some(language::proto::serialize_timestamp(message_id.0)), role: metadata.role.to_proto() as i32, status: Some(metadata.status.to_proto()), timestamp: Some(language::proto::serialize_timestamp(metadata.timestamp)), version: language::proto::serialize_version(version), }, )), }, Self::UpdateSummary { summary, version } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::UpdateSummary( proto::context_operation::UpdateSummary { summary: summary.text.clone(), done: summary.done, timestamp: Some(language::proto::serialize_timestamp(summary.timestamp)), version: language::proto::serialize_version(version), }, )), }, Self::SlashCommandFinished { id, output_range, sections, version, } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::SlashCommandFinished( proto::context_operation::SlashCommandFinished { id: Some(language::proto::serialize_timestamp(id.0)), output_range: Some(language::proto::serialize_anchor_range( output_range.clone(), )), sections: sections .iter() .map(|section| { let icon_name: &'static str = section.icon.into(); proto::SlashCommandOutputSection { range: Some(language::proto::serialize_anchor_range( section.range.clone(), )), icon_name: icon_name.to_string(), label: section.label.to_string(), } }) .collect(), version: language::proto::serialize_version(version), }, )), }, Self::BufferOperation(operation) => proto::ContextOperation { variant: Some(proto::context_operation::Variant::BufferOperation( proto::context_operation::BufferOperation { operation: Some(language::proto::serialize_operation(operation)), }, )), }, } } fn timestamp(&self) -> clock::Lamport { match self { Self::InsertMessage { anchor, .. } => anchor.id.0, Self::UpdateMessage { metadata, .. } => metadata.timestamp, Self::UpdateSummary { summary, .. } => summary.timestamp, Self::SlashCommandFinished { id, .. } => id.0, Self::BufferOperation(_) => { panic!("reading the timestamp of a buffer operation is not supported") } } } /// Returns the current version of the context operation. pub fn version(&self) -> &clock::Global { match self { Self::InsertMessage { version, .. } | Self::UpdateMessage { version, .. } | Self::UpdateSummary { version, .. } | Self::SlashCommandFinished { version, .. } => version, Self::BufferOperation(_) => { panic!("reading the version of a buffer operation is not supported") } } }} #[derive(Debug, Clone)]pub enum ContextEvent { ShowAssistError(SharedString), MessagesEdited, SummaryChanged, StreamedCompletion, WorkflowStepsUpdated { removed: Vec<Range<language::Anchor>>, updated: Vec<Range<language::Anchor>>, }, PendingSlashCommandsUpdated { removed: Vec<Range<language::Anchor>>, updated: Vec<PendingSlashCommand>, }, SlashCommandFinished { output_range: Range<language::Anchor>, sections: Vec<SlashCommandOutputSection<language::Anchor>>, run_commands_in_output: bool, expand_result: bool, }, UsePendingTools, ToolFinished { tool_use_id: Arc<str>, output_range: Range<language::Anchor>, }, Operation(ContextOperation),} #[derive(Clone, Default, Debug)]pub struct ContextSummary { pub text: String, done: bool, timestamp: clock::Lamport,} #[derive(Clone, Debug, Eq, PartialEq)]pub struct MessageAnchor { pub id: MessageId, pub start: language::Anchor,} #[derive(Clone, Debug, Eq, PartialEq)]pub enum CacheStatus { Pending, Cached,} #[derive(Clone, Debug, Eq, PartialEq)]pub struct MessageCacheMetadata { pub is_anchor: bool, pub is_final_anchor: bool, pub status: CacheStatus, pub cached_at: clock::Global,} #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]pub struct MessageMetadata { pub role: Role, pub status: MessageStatus, pub(crate) timestamp: clock::Lamport, #[serde(skip)] pub cache: Option<MessageCacheMetadata>,} impl From<&Message> for MessageMetadata { fn from(message: &Message) -> Self { Self { role: message.role, status: message.status.clone(), timestamp: message.id.0, cache: message.cache.clone(), } }} impl MessageMetadata { pub fn is_cache_valid(&self, buffer: &BufferSnapshot, range: &Range<usize>) -> bool { let result = match &self.cache { Some(MessageCacheMetadata { cached_at, .. }) => !buffer.has_edits_since_in_range( &cached_at, Range { start: buffer.anchor_at(range.start, Bias::Right), end: buffer.anchor_at(range.end, Bias::Left), }, ), _ => false, }; result }} #[derive(Clone, Debug)]pub struct Message { pub offset_range: Range<usize>, pub index_range: Range<usize>, pub anchor_range: Range<language::Anchor>, pub id: MessageId, pub role: Role, pub status: MessageStatus, pub cache: Option<MessageCacheMetadata>,} #[derive(Debug, Clone)]pub enum Content { Image { anchor: language::Anchor, image_id: u64, render_image: Arc<RenderImage>, image: Shared<Task<Option<LanguageModelImage>>>, }, ToolUse { range: Range<language::Anchor>, tool_use: LanguageModelToolUse, }, ToolResult { range: Range<language::Anchor>, tool_use_id: Arc<str>, },} impl Content { fn range(&self) -> Range<language::Anchor> { match self { Self::Image { anchor, .. } => *anchor..*anchor, Self::ToolUse { range, .. } | Self::ToolResult { range, .. } => range.clone(), } } fn cmp(&self, other: &Self, buffer: &BufferSnapshot) -> Ordering { let self_range = self.range(); let other_range = other.range(); if self_range.end.cmp(&other_range.start, buffer).is_lt() { Ordering::Less } else if self_range.start.cmp(&other_range.end, buffer).is_gt() { Ordering::Greater } else { Ordering::Equal } }} struct PendingCompletion { id: usize, assistant_message_id: MessageId, _task: Task<()>,} #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]pub struct SlashCommandId(clock::Lamport); #[derive(Clone, Debug)]pub struct XmlTag { pub kind: XmlTagKind, pub range: Range<text::Anchor>, pub is_open_tag: bool,} #[derive(Copy, Clone, Debug, strum::EnumString, PartialEq, Eq, strum::AsRefStr)]#[strum(serialize_all = "snake_case")]pub enum XmlTagKind { Step, Edit, Path, Search, Within, Operation, Description,} pub struct Context { id: ContextId, timestamp: clock::Lamport, version: clock::Global, pending_ops: Vec<ContextOperation>, operations: Vec<ContextOperation>, buffer: Model<Buffer>, pending_slash_commands: Vec<PendingSlashCommand>, edits_since_last_parse: language::Subscription, finished_slash_commands: HashSet<SlashCommandId>, slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>, pending_tool_uses_by_id: HashMap<Arc<str>, PendingToolUse>, message_anchors: Vec<MessageAnchor>, contents: Vec<Content>, messages_metadata: HashMap<MessageId, MessageMetadata>, summary: Option<ContextSummary>, pending_summary: Task<Option<()>>, completion_count: usize, pending_completions: Vec<PendingCompletion>, token_count: Option<usize>, pending_token_count: Task<Option<()>>, pending_save: Task<Result<()>>, pending_cache_warming_task: Task<Option<()>>, path: Option<PathBuf>, _subscriptions: Vec<Subscription>, telemetry: Option<Arc<Telemetry>>, language_registry: Arc<LanguageRegistry>, workflow_steps: Vec<WorkflowStep>, xml_tags: Vec<XmlTag>, project: Option<Model<Project>>, prompt_builder: Arc<PromptBuilder>,} trait ContextAnnotation { fn range(&self) -> &Range<language::Anchor>;} impl ContextAnnotation for PendingSlashCommand { fn range(&self) -> &Range<language::Anchor> { &self.source_range }} impl ContextAnnotation for WorkflowStep {Lines 1–500 of 3129. Load more
#[cfg(test)] mod context_tests; use crate::{ prompts::PromptBuilder, slash_command::SlashCommandLine, MessageId, MessageStatus, WorkflowStep, WorkflowStepEdit, WorkflowStepResolution, WorkflowSuggestionGroup, }; use anyhow::{anyhow, Context as _, Result}; use assistant_slash_command::{ SlashCommandOutput, SlashCommandOutputSection, SlashCommandRegistry, }; use assistant_tool::ToolRegistry; use client::{self, proto, telemetry::Telemetry}; use clock::ReplicaId; use collections::{HashMap, HashSet}; use feature_flags::{FeatureFlag, FeatureFlagAppExt}; use fs::{Fs, RemoveOptions}; use futures::{ future::{self, Shared}, FutureExt, StreamExt, }; use gpui::{ AppContext, AsyncAppContext, Context as _, EventEmitter, Model, ModelContext, RenderImage, SharedString, Subscription, Task, }; use language::{AnchorRangeExt, Bias, Buffer, LanguageRegistry, OffsetRangeExt, Point, ToOffset}; use language_model::{ LanguageModel, LanguageModelCacheConfiguration, LanguageModelCompletionEvent, LanguageModelImage, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, LanguageModelRequestTool, LanguageModelToolResult, LanguageModelToolUse, MessageContent, Role, StopReason, }; use open_ai::Model as OpenAiModel; use paths::contexts_dir; use project::Project; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use std::{ cmp::{self, max, Ordering}, fmt::Debug, iter, mem, ops::Range, path::{Path, PathBuf}, str::FromStr as _, sync::Arc, time::{Duration, Instant}, }; use telemetry_events::AssistantKind; use text::BufferSnapshot; use util::{post_inc, TryFutureExt}; use uuid::Uuid; #[derive(Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct ContextId(String); impl ContextId { pub fn new() -> Self { Self(Uuid::new_v4().to_string()) } pub fn from_proto(id: String) -> Self { Self(id) } pub fn to_proto(&self) -> String { self.0.clone() } } #[derive(Clone, Debug)] pub enum ContextOperation { InsertMessage { anchor: MessageAnchor, metadata: MessageMetadata, version: clock::Global, }, UpdateMessage { message_id: MessageId, metadata: MessageMetadata, version: clock::Global, }, UpdateSummary { summary: ContextSummary, version: clock::Global, }, SlashCommandFinished { id: SlashCommandId, output_range: Range<language::Anchor>, sections: Vec<SlashCommandOutputSection<language::Anchor>>, version: clock::Global, }, BufferOperation(language::Operation), } impl ContextOperation { pub fn from_proto(op: proto::ContextOperation) -> Result<Self> { match op.variant.context("invalid variant")? { proto::context_operation::Variant::InsertMessage(insert) => { let message = insert.message.context("invalid message")?; let id = MessageId(language::proto::deserialize_timestamp( message.id.context("invalid id")?, )); Ok(Self::InsertMessage { anchor: MessageAnchor { id, start: language::proto::deserialize_anchor( message.start.context("invalid anchor")?, ) .context("invalid anchor")?, }, metadata: MessageMetadata { role: Role::from_proto(message.role), status: MessageStatus::from_proto( message.status.context("invalid status")?, ), timestamp: id.0, cache: None, }, version: language::proto::deserialize_version(&insert.version), }) } proto::context_operation::Variant::UpdateMessage(update) => Ok(Self::UpdateMessage { message_id: MessageId(language::proto::deserialize_timestamp( update.message_id.context("invalid message id")?, )), metadata: MessageMetadata { role: Role::from_proto(update.role), status: MessageStatus::from_proto(update.status.context("invalid status")?), timestamp: language::proto::deserialize_timestamp( update.timestamp.context("invalid timestamp")?, ), cache: None, }, version: language::proto::deserialize_version(&update.version), }), proto::context_operation::Variant::UpdateSummary(update) => Ok(Self::UpdateSummary { summary: ContextSummary { text: update.summary, done: update.done, timestamp: language::proto::deserialize_timestamp( update.timestamp.context("invalid timestamp")?, ), }, version: language::proto::deserialize_version(&update.version), }), proto::context_operation::Variant::SlashCommandFinished(finished) => { Ok(Self::SlashCommandFinished { id: SlashCommandId(language::proto::deserialize_timestamp( finished.id.context("invalid id")?, )), output_range: language::proto::deserialize_anchor_range( finished.output_range.context("invalid range")?, )?, sections: finished .sections .into_iter() .map(|section| { Ok(SlashCommandOutputSection { range: language::proto::deserialize_anchor_range( section.range.context("invalid range")?, )?, icon: section.icon_name.parse()?, label: section.label.into(), }) }) .collect::<Result<Vec<_>>>()?, version: language::proto::deserialize_version(&finished.version), }) } proto::context_operation::Variant::BufferOperation(op) => Ok(Self::BufferOperation( language::proto::deserialize_operation( op.operation.context("invalid buffer operation")?, )?, )), } } pub fn to_proto(&self) -> proto::ContextOperation { match self { Self::InsertMessage { anchor, metadata, version, } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::InsertMessage( proto::context_operation::InsertMessage { message: Some(proto::ContextMessage { id: Some(language::proto::serialize_timestamp(anchor.id.0)), start: Some(language::proto::serialize_anchor(&anchor.start)), role: metadata.role.to_proto() as i32, status: Some(metadata.status.to_proto()), }), version: language::proto::serialize_version(version), }, )), }, Self::UpdateMessage { message_id, metadata, version, } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::UpdateMessage( proto::context_operation::UpdateMessage { message_id: Some(language::proto::serialize_timestamp(message_id.0)), role: metadata.role.to_proto() as i32, status: Some(metadata.status.to_proto()), timestamp: Some(language::proto::serialize_timestamp(metadata.timestamp)), version: language::proto::serialize_version(version), }, )), }, Self::UpdateSummary { summary, version } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::UpdateSummary( proto::context_operation::UpdateSummary { summary: summary.text.clone(), done: summary.done, timestamp: Some(language::proto::serialize_timestamp(summary.timestamp)), version: language::proto::serialize_version(version), }, )), }, Self::SlashCommandFinished { id, output_range, sections, version, } => proto::ContextOperation { variant: Some(proto::context_operation::Variant::SlashCommandFinished( proto::context_operation::SlashCommandFinished { id: Some(language::proto::serialize_timestamp(id.0)), output_range: Some(language::proto::serialize_anchor_range( output_range.clone(), )), sections: sections .iter() .map(|section| { let icon_name: &'static str = section.icon.into(); proto::SlashCommandOutputSection { range: Some(language::proto::serialize_anchor_range( section.range.clone(), )), icon_name: icon_name.to_string(), label: section.label.to_string(), } }) .collect(), version: language::proto::serialize_version(version), }, )), }, Self::BufferOperation(operation) => proto::ContextOperation { variant: Some(proto::context_operation::Variant::BufferOperation( proto::context_operation::BufferOperation { operation: Some(language::proto::serialize_operation(operation)), }, )), }, } } fn timestamp(&self) -> clock::Lamport { match self { Self::InsertMessage { anchor, .. } => anchor.id.0, Self::UpdateMessage { metadata, .. } => metadata.timestamp, Self::UpdateSummary { summary, .. } => summary.timestamp, Self::SlashCommandFinished { id, .. } => id.0, Self::BufferOperation(_) => { panic!("reading the timestamp of a buffer operation is not supported") } } } /// Returns the current version of the context operation. pub fn version(&self) -> &clock::Global { match self { Self::InsertMessage { version, .. } | Self::UpdateMessage { version, .. } | Self::UpdateSummary { version, .. } | Self::SlashCommandFinished { version, .. } => version, Self::BufferOperation(_) => { panic!("reading the version of a buffer operation is not supported") } } } } #[derive(Debug, Clone)] pub enum ContextEvent { ShowAssistError(SharedString), MessagesEdited, SummaryChanged, StreamedCompletion, WorkflowStepsUpdated { removed: Vec<Range<language::Anchor>>, updated: Vec<Range<language::Anchor>>, }, PendingSlashCommandsUpdated { removed: Vec<Range<language::Anchor>>, updated: Vec<PendingSlashCommand>, }, SlashCommandFinished { output_range: Range<language::Anchor>, sections: Vec<SlashCommandOutputSection<language::Anchor>>, run_commands_in_output: bool, expand_result: bool, }, UsePendingTools, ToolFinished { tool_use_id: Arc<str>, output_range: Range<language::Anchor>, }, Operation(ContextOperation), } #[derive(Clone, Default, Debug)] pub struct ContextSummary { pub text: String, done: bool, timestamp: clock::Lamport, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct MessageAnchor { pub id: MessageId, pub start: language::Anchor, } #[derive(Clone, Debug, Eq, PartialEq)] pub enum CacheStatus { Pending, Cached, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct MessageCacheMetadata { pub is_anchor: bool, pub is_final_anchor: bool, pub status: CacheStatus, pub cached_at: clock::Global, } #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct MessageMetadata { pub role: Role, pub status: MessageStatus, pub(crate) timestamp: clock::Lamport, #[serde(skip)] pub cache: Option<MessageCacheMetadata>, } impl From<&Message> for MessageMetadata { fn from(message: &Message) -> Self { Self { role: message.role, status: message.status.clone(), timestamp: message.id.0, cache: message.cache.clone(), } } } impl MessageMetadata { pub fn is_cache_valid(&self, buffer: &BufferSnapshot, range: &Range<usize>) -> bool { let result = match &self.cache { Some(MessageCacheMetadata { cached_at, .. }) => !buffer.has_edits_since_in_range( &cached_at, Range { start: buffer.anchor_at(range.start, Bias::Right), end: buffer.anchor_at(range.end, Bias::Left), }, ), _ => false, }; result } } #[derive(Clone, Debug)] pub struct Message { pub offset_range: Range<usize>, pub index_range: Range<usize>, pub anchor_range: Range<language::Anchor>, pub id: MessageId, pub role: Role, pub status: MessageStatus, pub cache: Option<MessageCacheMetadata>, } #[derive(Debug, Clone)] pub enum Content { Image { anchor: language::Anchor, image_id: u64, render_image: Arc<RenderImage>, image: Shared<Task<Option<LanguageModelImage>>>, }, ToolUse { range: Range<language::Anchor>, tool_use: LanguageModelToolUse, }, ToolResult { range: Range<language::Anchor>, tool_use_id: Arc<str>, }, } impl Content { fn range(&self) -> Range<language::Anchor> { match self { Self::Image { anchor, .. } => *anchor..*anchor, Self::ToolUse { range, .. } | Self::ToolResult { range, .. } => range.clone(), } } fn cmp(&self, other: &Self, buffer: &BufferSnapshot) -> Ordering { let self_range = self.range(); let other_range = other.range(); if self_range.end.cmp(&other_range.start, buffer).is_lt() { Ordering::Less } else if self_range.start.cmp(&other_range.end, buffer).is_gt() { Ordering::Greater } else { Ordering::Equal } } } struct PendingCompletion { id: usize, assistant_message_id: MessageId, _task: Task<()>, } #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct SlashCommandId(clock::Lamport); #[derive(Clone, Debug)] pub struct XmlTag { pub kind: XmlTagKind, pub range: Range<text::Anchor>, pub is_open_tag: bool, } #[derive(Copy, Clone, Debug, strum::EnumString, PartialEq, Eq, strum::AsRefStr)] #[strum(serialize_all = "snake_case")] pub enum XmlTagKind { Step, Edit, Path, Search, Within, Operation, Description, } pub struct Context { id: ContextId, timestamp: clock::Lamport, version: clock::Global, pending_ops: Vec<ContextOperation>, operations: Vec<ContextOperation>, buffer: Model<Buffer>, pending_slash_commands: Vec<PendingSlashCommand>, edits_since_last_parse: language::Subscription, finished_slash_commands: HashSet<SlashCommandId>, slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>, pending_tool_uses_by_id: HashMap<Arc<str>, PendingToolUse>, message_anchors: Vec<MessageAnchor>, contents: Vec<Content>, messages_metadata: HashMap<MessageId, MessageMetadata>, summary: Option<ContextSummary>, pending_summary: Task<Option<()>>, completion_count: usize, pending_completions: Vec<PendingCompletion>, token_count: Option<usize>, pending_token_count: Task<Option<()>>, pending_save: Task<Result<()>>, pending_cache_warming_task: Task<Option<()>>, path: Option<PathBuf>, _subscriptions: Vec<Subscription>, telemetry: Option<Arc<Telemetry>>, language_registry: Arc<LanguageRegistry>, workflow_steps: Vec<WorkflowStep>, xml_tags: Vec<XmlTag>, project: Option<Model<Project>>, prompt_builder: Arc<PromptBuilder>, } trait ContextAnnotation { fn range(&self) -> &Range<language::Anchor>; } impl ContextAnnotation for PendingSlashCommand { fn range(&self) -> &Range<language::Anchor> { &self.source_range } } impl ContextAnnotation for WorkflowStep {