context.rs

   1#[cfg(test)]
   2mod context_tests;
   3
   4use crate::patch::{AssistantEdit, AssistantPatch, AssistantPatchStatus};
   5use anyhow::{anyhow, Context as _, Result};
   6use assistant_slash_command::{
   7    SlashCommandContent, SlashCommandEvent, SlashCommandLine, SlashCommandOutputSection,
   8    SlashCommandResult, SlashCommandWorkingSet,
   9};
  10use assistant_slash_commands::FileCommandMetadata;
  11use client::{self, proto, telemetry::Telemetry};
  12use clock::ReplicaId;
  13use collections::{HashMap, HashSet};
  14use fs::{Fs, RemoveOptions};
  15use futures::{future::Shared, FutureExt, StreamExt};
  16use gpui::{
  17    App, AppContext as _, Context, Entity, EventEmitter, RenderImage, SharedString, Subscription,
  18    Task,
  19};
  20use language::{AnchorRangeExt, Bias, Buffer, LanguageRegistry, OffsetRangeExt, Point, ToOffset};
  21use language_model::{
  22    LanguageModel, LanguageModelCacheConfiguration, LanguageModelCompletionEvent,
  23    LanguageModelImage, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage,
  24    LanguageModelToolUseId, MessageContent, Role, StopReason,
  25};
  26use language_models::{
  27    provider::cloud::{MaxMonthlySpendReachedError, PaymentRequiredError},
  28    report_assistant_event,
  29};
  30use open_ai::Model as OpenAiModel;
  31use paths::contexts_dir;
  32use project::Project;
  33use prompt_library::PromptBuilder;
  34use serde::{Deserialize, Serialize};
  35use smallvec::SmallVec;
  36use std::{
  37    cmp::{max, Ordering},
  38    fmt::Debug,
  39    iter, mem,
  40    ops::Range,
  41    path::{Path, PathBuf},
  42    str::FromStr as _,
  43    sync::Arc,
  44    time::{Duration, Instant},
  45};
  46use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
  47use text::{BufferSnapshot, ToPoint};
  48use ui::IconName;
  49use util::{post_inc, ResultExt, TryFutureExt};
  50use uuid::Uuid;
  51
  52#[derive(Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
  53pub struct ContextId(String);
  54
  55impl ContextId {
  56    pub fn new() -> Self {
  57        Self(Uuid::new_v4().to_string())
  58    }
  59
  60    pub fn from_proto(id: String) -> Self {
  61        Self(id)
  62    }
  63
  64    pub fn to_proto(&self) -> String {
  65        self.0.clone()
  66    }
  67}
  68
  69#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
  70pub struct MessageId(pub clock::Lamport);
  71
  72impl MessageId {
  73    pub fn as_u64(self) -> u64 {
  74        self.0.as_u64()
  75    }
  76}
  77
  78#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
  79pub enum MessageStatus {
  80    Pending,
  81    Done,
  82    Error(SharedString),
  83    Canceled,
  84}
  85
  86impl MessageStatus {
  87    pub fn from_proto(status: proto::ContextMessageStatus) -> MessageStatus {
  88        match status.variant {
  89            Some(proto::context_message_status::Variant::Pending(_)) => MessageStatus::Pending,
  90            Some(proto::context_message_status::Variant::Done(_)) => MessageStatus::Done,
  91            Some(proto::context_message_status::Variant::Error(error)) => {
  92                MessageStatus::Error(error.message.into())
  93            }
  94            Some(proto::context_message_status::Variant::Canceled(_)) => MessageStatus::Canceled,
  95            None => MessageStatus::Pending,
  96        }
  97    }
  98
  99    pub fn to_proto(&self) -> proto::ContextMessageStatus {
 100        match self {
 101            MessageStatus::Pending => proto::ContextMessageStatus {
 102                variant: Some(proto::context_message_status::Variant::Pending(
 103                    proto::context_message_status::Pending {},
 104                )),
 105            },
 106            MessageStatus::Done => proto::ContextMessageStatus {
 107                variant: Some(proto::context_message_status::Variant::Done(
 108                    proto::context_message_status::Done {},
 109                )),
 110            },
 111            MessageStatus::Error(message) => proto::ContextMessageStatus {
 112                variant: Some(proto::context_message_status::Variant::Error(
 113                    proto::context_message_status::Error {
 114                        message: message.to_string(),
 115                    },
 116                )),
 117            },
 118            MessageStatus::Canceled => proto::ContextMessageStatus {
 119                variant: Some(proto::context_message_status::Variant::Canceled(
 120                    proto::context_message_status::Canceled {},
 121                )),
 122            },
 123        }
 124    }
 125}
 126
 127#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 128pub enum RequestType {
 129    /// Request a normal chat response from the model.
 130    Chat,
 131    /// Add a preamble to the message, which tells the model to return a structured response that suggests edits.
 132    SuggestEdits,
 133}
 134
 135#[derive(Clone, Debug)]
 136pub enum ContextOperation {
 137    InsertMessage {
 138        anchor: MessageAnchor,
 139        metadata: MessageMetadata,
 140        version: clock::Global,
 141    },
 142    UpdateMessage {
 143        message_id: MessageId,
 144        metadata: MessageMetadata,
 145        version: clock::Global,
 146    },
 147    UpdateSummary {
 148        summary: ContextSummary,
 149        version: clock::Global,
 150    },
 151    SlashCommandStarted {
 152        id: InvokedSlashCommandId,
 153        output_range: Range<language::Anchor>,
 154        name: String,
 155        version: clock::Global,
 156    },
 157    SlashCommandFinished {
 158        id: InvokedSlashCommandId,
 159        timestamp: clock::Lamport,
 160        error_message: Option<String>,
 161        version: clock::Global,
 162    },
 163    SlashCommandOutputSectionAdded {
 164        timestamp: clock::Lamport,
 165        section: SlashCommandOutputSection<language::Anchor>,
 166        version: clock::Global,
 167    },
 168    BufferOperation(language::Operation),
 169}
 170
 171impl ContextOperation {
 172    pub fn from_proto(op: proto::ContextOperation) -> Result<Self> {
 173        match op.variant.context("invalid variant")? {
 174            proto::context_operation::Variant::InsertMessage(insert) => {
 175                let message = insert.message.context("invalid message")?;
 176                let id = MessageId(language::proto::deserialize_timestamp(
 177                    message.id.context("invalid id")?,
 178                ));
 179                Ok(Self::InsertMessage {
 180                    anchor: MessageAnchor {
 181                        id,
 182                        start: language::proto::deserialize_anchor(
 183                            message.start.context("invalid anchor")?,
 184                        )
 185                        .context("invalid anchor")?,
 186                    },
 187                    metadata: MessageMetadata {
 188                        role: Role::from_proto(message.role),
 189                        status: MessageStatus::from_proto(
 190                            message.status.context("invalid status")?,
 191                        ),
 192                        timestamp: id.0,
 193                        cache: None,
 194                    },
 195                    version: language::proto::deserialize_version(&insert.version),
 196                })
 197            }
 198            proto::context_operation::Variant::UpdateMessage(update) => Ok(Self::UpdateMessage {
 199                message_id: MessageId(language::proto::deserialize_timestamp(
 200                    update.message_id.context("invalid message id")?,
 201                )),
 202                metadata: MessageMetadata {
 203                    role: Role::from_proto(update.role),
 204                    status: MessageStatus::from_proto(update.status.context("invalid status")?),
 205                    timestamp: language::proto::deserialize_timestamp(
 206                        update.timestamp.context("invalid timestamp")?,
 207                    ),
 208                    cache: None,
 209                },
 210                version: language::proto::deserialize_version(&update.version),
 211            }),
 212            proto::context_operation::Variant::UpdateSummary(update) => Ok(Self::UpdateSummary {
 213                summary: ContextSummary {
 214                    text: update.summary,
 215                    done: update.done,
 216                    timestamp: language::proto::deserialize_timestamp(
 217                        update.timestamp.context("invalid timestamp")?,
 218                    ),
 219                },
 220                version: language::proto::deserialize_version(&update.version),
 221            }),
 222            proto::context_operation::Variant::SlashCommandStarted(message) => {
 223                Ok(Self::SlashCommandStarted {
 224                    id: InvokedSlashCommandId(language::proto::deserialize_timestamp(
 225                        message.id.context("invalid id")?,
 226                    )),
 227                    output_range: language::proto::deserialize_anchor_range(
 228                        message.output_range.context("invalid range")?,
 229                    )?,
 230                    name: message.name,
 231                    version: language::proto::deserialize_version(&message.version),
 232                })
 233            }
 234            proto::context_operation::Variant::SlashCommandOutputSectionAdded(message) => {
 235                let section = message.section.context("missing section")?;
 236                Ok(Self::SlashCommandOutputSectionAdded {
 237                    timestamp: language::proto::deserialize_timestamp(
 238                        message.timestamp.context("missing timestamp")?,
 239                    ),
 240                    section: SlashCommandOutputSection {
 241                        range: language::proto::deserialize_anchor_range(
 242                            section.range.context("invalid range")?,
 243                        )?,
 244                        icon: section.icon_name.parse()?,
 245                        label: section.label.into(),
 246                        metadata: section
 247                            .metadata
 248                            .and_then(|metadata| serde_json::from_str(&metadata).log_err()),
 249                    },
 250                    version: language::proto::deserialize_version(&message.version),
 251                })
 252            }
 253            proto::context_operation::Variant::SlashCommandCompleted(message) => {
 254                Ok(Self::SlashCommandFinished {
 255                    id: InvokedSlashCommandId(language::proto::deserialize_timestamp(
 256                        message.id.context("invalid id")?,
 257                    )),
 258                    timestamp: language::proto::deserialize_timestamp(
 259                        message.timestamp.context("missing timestamp")?,
 260                    ),
 261                    error_message: message.error_message,
 262                    version: language::proto::deserialize_version(&message.version),
 263                })
 264            }
 265            proto::context_operation::Variant::BufferOperation(op) => Ok(Self::BufferOperation(
 266                language::proto::deserialize_operation(
 267                    op.operation.context("invalid buffer operation")?,
 268                )?,
 269            )),
 270        }
 271    }
 272
 273    pub fn to_proto(&self) -> proto::ContextOperation {
 274        match self {
 275            Self::InsertMessage {
 276                anchor,
 277                metadata,
 278                version,
 279            } => proto::ContextOperation {
 280                variant: Some(proto::context_operation::Variant::InsertMessage(
 281                    proto::context_operation::InsertMessage {
 282                        message: Some(proto::ContextMessage {
 283                            id: Some(language::proto::serialize_timestamp(anchor.id.0)),
 284                            start: Some(language::proto::serialize_anchor(&anchor.start)),
 285                            role: metadata.role.to_proto() as i32,
 286                            status: Some(metadata.status.to_proto()),
 287                        }),
 288                        version: language::proto::serialize_version(version),
 289                    },
 290                )),
 291            },
 292            Self::UpdateMessage {
 293                message_id,
 294                metadata,
 295                version,
 296            } => proto::ContextOperation {
 297                variant: Some(proto::context_operation::Variant::UpdateMessage(
 298                    proto::context_operation::UpdateMessage {
 299                        message_id: Some(language::proto::serialize_timestamp(message_id.0)),
 300                        role: metadata.role.to_proto() as i32,
 301                        status: Some(metadata.status.to_proto()),
 302                        timestamp: Some(language::proto::serialize_timestamp(metadata.timestamp)),
 303                        version: language::proto::serialize_version(version),
 304                    },
 305                )),
 306            },
 307            Self::UpdateSummary { summary, version } => proto::ContextOperation {
 308                variant: Some(proto::context_operation::Variant::UpdateSummary(
 309                    proto::context_operation::UpdateSummary {
 310                        summary: summary.text.clone(),
 311                        done: summary.done,
 312                        timestamp: Some(language::proto::serialize_timestamp(summary.timestamp)),
 313                        version: language::proto::serialize_version(version),
 314                    },
 315                )),
 316            },
 317            Self::SlashCommandStarted {
 318                id,
 319                output_range,
 320                name,
 321                version,
 322            } => proto::ContextOperation {
 323                variant: Some(proto::context_operation::Variant::SlashCommandStarted(
 324                    proto::context_operation::SlashCommandStarted {
 325                        id: Some(language::proto::serialize_timestamp(id.0)),
 326                        output_range: Some(language::proto::serialize_anchor_range(
 327                            output_range.clone(),
 328                        )),
 329                        name: name.clone(),
 330                        version: language::proto::serialize_version(version),
 331                    },
 332                )),
 333            },
 334            Self::SlashCommandOutputSectionAdded {
 335                timestamp,
 336                section,
 337                version,
 338            } => proto::ContextOperation {
 339                variant: Some(
 340                    proto::context_operation::Variant::SlashCommandOutputSectionAdded(
 341                        proto::context_operation::SlashCommandOutputSectionAdded {
 342                            timestamp: Some(language::proto::serialize_timestamp(*timestamp)),
 343                            section: Some({
 344                                let icon_name: &'static str = section.icon.into();
 345                                proto::SlashCommandOutputSection {
 346                                    range: Some(language::proto::serialize_anchor_range(
 347                                        section.range.clone(),
 348                                    )),
 349                                    icon_name: icon_name.to_string(),
 350                                    label: section.label.to_string(),
 351                                    metadata: section.metadata.as_ref().and_then(|metadata| {
 352                                        serde_json::to_string(metadata).log_err()
 353                                    }),
 354                                }
 355                            }),
 356                            version: language::proto::serialize_version(version),
 357                        },
 358                    ),
 359                ),
 360            },
 361            Self::SlashCommandFinished {
 362                id,
 363                timestamp,
 364                error_message,
 365                version,
 366            } => proto::ContextOperation {
 367                variant: Some(proto::context_operation::Variant::SlashCommandCompleted(
 368                    proto::context_operation::SlashCommandCompleted {
 369                        id: Some(language::proto::serialize_timestamp(id.0)),
 370                        timestamp: Some(language::proto::serialize_timestamp(*timestamp)),
 371                        error_message: error_message.clone(),
 372                        version: language::proto::serialize_version(version),
 373                    },
 374                )),
 375            },
 376            Self::BufferOperation(operation) => proto::ContextOperation {
 377                variant: Some(proto::context_operation::Variant::BufferOperation(
 378                    proto::context_operation::BufferOperation {
 379                        operation: Some(language::proto::serialize_operation(operation)),
 380                    },
 381                )),
 382            },
 383        }
 384    }
 385
 386    fn timestamp(&self) -> clock::Lamport {
 387        match self {
 388            Self::InsertMessage { anchor, .. } => anchor.id.0,
 389            Self::UpdateMessage { metadata, .. } => metadata.timestamp,
 390            Self::UpdateSummary { summary, .. } => summary.timestamp,
 391            Self::SlashCommandStarted { id, .. } => id.0,
 392            Self::SlashCommandOutputSectionAdded { timestamp, .. }
 393            | Self::SlashCommandFinished { timestamp, .. } => *timestamp,
 394            Self::BufferOperation(_) => {
 395                panic!("reading the timestamp of a buffer operation is not supported")
 396            }
 397        }
 398    }
 399
 400    /// Returns the current version of the context operation.
 401    pub fn version(&self) -> &clock::Global {
 402        match self {
 403            Self::InsertMessage { version, .. }
 404            | Self::UpdateMessage { version, .. }
 405            | Self::UpdateSummary { version, .. }
 406            | Self::SlashCommandStarted { version, .. }
 407            | Self::SlashCommandOutputSectionAdded { version, .. }
 408            | Self::SlashCommandFinished { version, .. } => version,
 409            Self::BufferOperation(_) => {
 410                panic!("reading the version of a buffer operation is not supported")
 411            }
 412        }
 413    }
 414}
 415
 416#[derive(Debug, Clone)]
 417pub enum ContextEvent {
 418    ShowAssistError(SharedString),
 419    ShowPaymentRequiredError,
 420    ShowMaxMonthlySpendReachedError,
 421    MessagesEdited,
 422    SummaryChanged,
 423    StreamedCompletion,
 424    PatchesUpdated {
 425        removed: Vec<Range<language::Anchor>>,
 426        updated: Vec<Range<language::Anchor>>,
 427    },
 428    InvokedSlashCommandChanged {
 429        command_id: InvokedSlashCommandId,
 430    },
 431    ParsedSlashCommandsUpdated {
 432        removed: Vec<Range<language::Anchor>>,
 433        updated: Vec<ParsedSlashCommand>,
 434    },
 435    SlashCommandOutputSectionAdded {
 436        section: SlashCommandOutputSection<language::Anchor>,
 437    },
 438    Operation(ContextOperation),
 439}
 440
 441#[derive(Clone, Default, Debug)]
 442pub struct ContextSummary {
 443    pub text: String,
 444    done: bool,
 445    timestamp: clock::Lamport,
 446}
 447
 448#[derive(Clone, Debug, Eq, PartialEq)]
 449pub struct MessageAnchor {
 450    pub id: MessageId,
 451    pub start: language::Anchor,
 452}
 453
 454#[derive(Clone, Debug, Eq, PartialEq)]
 455pub enum CacheStatus {
 456    Pending,
 457    Cached,
 458}
 459
 460#[derive(Clone, Debug, Eq, PartialEq)]
 461pub struct MessageCacheMetadata {
 462    pub is_anchor: bool,
 463    pub is_final_anchor: bool,
 464    pub status: CacheStatus,
 465    pub cached_at: clock::Global,
 466}
 467
 468#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
 469pub struct MessageMetadata {
 470    pub role: Role,
 471    pub status: MessageStatus,
 472    pub timestamp: clock::Lamport,
 473    #[serde(skip)]
 474    pub cache: Option<MessageCacheMetadata>,
 475}
 476
 477impl From<&Message> for MessageMetadata {
 478    fn from(message: &Message) -> Self {
 479        Self {
 480            role: message.role,
 481            status: message.status.clone(),
 482            timestamp: message.id.0,
 483            cache: message.cache.clone(),
 484        }
 485    }
 486}
 487
 488impl MessageMetadata {
 489    pub fn is_cache_valid(&self, buffer: &BufferSnapshot, range: &Range<usize>) -> bool {
 490        let result = match &self.cache {
 491            Some(MessageCacheMetadata { cached_at, .. }) => !buffer.has_edits_since_in_range(
 492                &cached_at,
 493                Range {
 494                    start: buffer.anchor_at(range.start, Bias::Right),
 495                    end: buffer.anchor_at(range.end, Bias::Left),
 496                },
 497            ),
 498            _ => false,
 499        };
 500        result
 501    }
 502}
 503
 504#[derive(Clone, Debug)]
 505pub struct Message {
 506    pub offset_range: Range<usize>,
 507    pub index_range: Range<usize>,
 508    pub anchor_range: Range<language::Anchor>,
 509    pub id: MessageId,
 510    pub role: Role,
 511    pub status: MessageStatus,
 512    pub cache: Option<MessageCacheMetadata>,
 513}
 514
 515#[derive(Debug, Clone)]
 516pub enum Content {
 517    Image {
 518        anchor: language::Anchor,
 519        image_id: u64,
 520        render_image: Arc<RenderImage>,
 521        image: Shared<Task<Option<LanguageModelImage>>>,
 522    },
 523}
 524
 525impl Content {
 526    fn range(&self) -> Range<language::Anchor> {
 527        match self {
 528            Self::Image { anchor, .. } => *anchor..*anchor,
 529        }
 530    }
 531
 532    fn cmp(&self, other: &Self, buffer: &BufferSnapshot) -> Ordering {
 533        let self_range = self.range();
 534        let other_range = other.range();
 535        if self_range.end.cmp(&other_range.start, buffer).is_lt() {
 536            Ordering::Less
 537        } else if self_range.start.cmp(&other_range.end, buffer).is_gt() {
 538            Ordering::Greater
 539        } else {
 540            Ordering::Equal
 541        }
 542    }
 543}
 544
 545struct PendingCompletion {
 546    id: usize,
 547    assistant_message_id: MessageId,
 548    _task: Task<()>,
 549}
 550
 551#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
 552pub struct InvokedSlashCommandId(clock::Lamport);
 553
 554#[derive(Clone, Debug)]
 555pub struct XmlTag {
 556    pub kind: XmlTagKind,
 557    pub range: Range<text::Anchor>,
 558    pub is_open_tag: bool,
 559}
 560
 561#[derive(Copy, Clone, Debug, strum::EnumString, PartialEq, Eq, strum::AsRefStr)]
 562#[strum(serialize_all = "snake_case")]
 563pub enum XmlTagKind {
 564    Patch,
 565    Title,
 566    Edit,
 567    Path,
 568    Description,
 569    OldText,
 570    NewText,
 571    Operation,
 572}
 573
 574pub struct AssistantContext {
 575    id: ContextId,
 576    timestamp: clock::Lamport,
 577    version: clock::Global,
 578    pending_ops: Vec<ContextOperation>,
 579    operations: Vec<ContextOperation>,
 580    buffer: Entity<Buffer>,
 581    parsed_slash_commands: Vec<ParsedSlashCommand>,
 582    invoked_slash_commands: HashMap<InvokedSlashCommandId, InvokedSlashCommand>,
 583    edits_since_last_parse: language::Subscription,
 584    slash_commands: Arc<SlashCommandWorkingSet>,
 585    slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>,
 586    message_anchors: Vec<MessageAnchor>,
 587    contents: Vec<Content>,
 588    messages_metadata: HashMap<MessageId, MessageMetadata>,
 589    summary: Option<ContextSummary>,
 590    pending_summary: Task<Option<()>>,
 591    completion_count: usize,
 592    pending_completions: Vec<PendingCompletion>,
 593    token_count: Option<usize>,
 594    pending_token_count: Task<Option<()>>,
 595    pending_save: Task<Result<()>>,
 596    pending_cache_warming_task: Task<Option<()>>,
 597    path: Option<PathBuf>,
 598    _subscriptions: Vec<Subscription>,
 599    telemetry: Option<Arc<Telemetry>>,
 600    language_registry: Arc<LanguageRegistry>,
 601    patches: Vec<AssistantPatch>,
 602    xml_tags: Vec<XmlTag>,
 603    project: Option<Entity<Project>>,
 604    prompt_builder: Arc<PromptBuilder>,
 605}
 606
 607trait ContextAnnotation {
 608    fn range(&self) -> &Range<language::Anchor>;
 609}
 610
 611impl ContextAnnotation for ParsedSlashCommand {
 612    fn range(&self) -> &Range<language::Anchor> {
 613        &self.source_range
 614    }
 615}
 616
 617impl ContextAnnotation for AssistantPatch {
 618    fn range(&self) -> &Range<language::Anchor> {
 619        &self.range
 620    }
 621}
 622
 623impl ContextAnnotation for XmlTag {
 624    fn range(&self) -> &Range<language::Anchor> {
 625        &self.range
 626    }
 627}
 628
 629impl EventEmitter<ContextEvent> for AssistantContext {}
 630
 631impl AssistantContext {
 632    pub fn local(
 633        language_registry: Arc<LanguageRegistry>,
 634        project: Option<Entity<Project>>,
 635        telemetry: Option<Arc<Telemetry>>,
 636        prompt_builder: Arc<PromptBuilder>,
 637        slash_commands: Arc<SlashCommandWorkingSet>,
 638        cx: &mut Context<Self>,
 639    ) -> Self {
 640        Self::new(
 641            ContextId::new(),
 642            ReplicaId::default(),
 643            language::Capability::ReadWrite,
 644            language_registry,
 645            prompt_builder,
 646            slash_commands,
 647            project,
 648            telemetry,
 649            cx,
 650        )
 651    }
 652
 653    #[allow(clippy::too_many_arguments)]
 654    pub fn new(
 655        id: ContextId,
 656        replica_id: ReplicaId,
 657        capability: language::Capability,
 658        language_registry: Arc<LanguageRegistry>,
 659        prompt_builder: Arc<PromptBuilder>,
 660        slash_commands: Arc<SlashCommandWorkingSet>,
 661        project: Option<Entity<Project>>,
 662        telemetry: Option<Arc<Telemetry>>,
 663        cx: &mut Context<Self>,
 664    ) -> Self {
 665        let buffer = cx.new(|_cx| {
 666            let buffer = Buffer::remote(
 667                language::BufferId::new(1).unwrap(),
 668                replica_id,
 669                capability,
 670                "",
 671            );
 672            buffer.set_language_registry(language_registry.clone());
 673            buffer
 674        });
 675        let edits_since_last_slash_command_parse =
 676            buffer.update(cx, |buffer, _| buffer.subscribe());
 677        let mut this = Self {
 678            id,
 679            timestamp: clock::Lamport::new(replica_id),
 680            version: clock::Global::new(),
 681            pending_ops: Vec::new(),
 682            operations: Vec::new(),
 683            message_anchors: Default::default(),
 684            contents: Default::default(),
 685            messages_metadata: Default::default(),
 686            parsed_slash_commands: Vec::new(),
 687            invoked_slash_commands: HashMap::default(),
 688            slash_command_output_sections: Vec::new(),
 689            edits_since_last_parse: edits_since_last_slash_command_parse,
 690            summary: None,
 691            pending_summary: Task::ready(None),
 692            completion_count: Default::default(),
 693            pending_completions: Default::default(),
 694            token_count: None,
 695            pending_token_count: Task::ready(None),
 696            pending_cache_warming_task: Task::ready(None),
 697            _subscriptions: vec![cx.subscribe(&buffer, Self::handle_buffer_event)],
 698            pending_save: Task::ready(Ok(())),
 699            path: None,
 700            buffer,
 701            telemetry,
 702            project,
 703            language_registry,
 704            slash_commands,
 705            patches: Vec::new(),
 706            xml_tags: Vec::new(),
 707            prompt_builder,
 708        };
 709
 710        let first_message_id = MessageId(clock::Lamport {
 711            replica_id: 0,
 712            value: 0,
 713        });
 714        let message = MessageAnchor {
 715            id: first_message_id,
 716            start: language::Anchor::MIN,
 717        };
 718        this.messages_metadata.insert(
 719            first_message_id,
 720            MessageMetadata {
 721                role: Role::User,
 722                status: MessageStatus::Done,
 723                timestamp: first_message_id.0,
 724                cache: None,
 725            },
 726        );
 727        this.message_anchors.push(message);
 728
 729        this.set_language(cx);
 730        this.count_remaining_tokens(cx);
 731        this
 732    }
 733
 734    pub(crate) fn serialize(&self, cx: &App) -> SavedContext {
 735        let buffer = self.buffer.read(cx);
 736        SavedContext {
 737            id: Some(self.id.clone()),
 738            zed: "context".into(),
 739            version: SavedContext::VERSION.into(),
 740            text: buffer.text(),
 741            messages: self
 742                .messages(cx)
 743                .map(|message| SavedMessage {
 744                    id: message.id,
 745                    start: message.offset_range.start,
 746                    metadata: self.messages_metadata[&message.id].clone(),
 747                })
 748                .collect(),
 749            summary: self
 750                .summary
 751                .as_ref()
 752                .map(|summary| summary.text.clone())
 753                .unwrap_or_default(),
 754            slash_command_output_sections: self
 755                .slash_command_output_sections
 756                .iter()
 757                .filter_map(|section| {
 758                    if section.is_valid(buffer) {
 759                        let range = section.range.to_offset(buffer);
 760                        Some(assistant_slash_command::SlashCommandOutputSection {
 761                            range,
 762                            icon: section.icon,
 763                            label: section.label.clone(),
 764                            metadata: section.metadata.clone(),
 765                        })
 766                    } else {
 767                        None
 768                    }
 769                })
 770                .collect(),
 771        }
 772    }
 773
 774    #[allow(clippy::too_many_arguments)]
 775    pub fn deserialize(
 776        saved_context: SavedContext,
 777        path: PathBuf,
 778        language_registry: Arc<LanguageRegistry>,
 779        prompt_builder: Arc<PromptBuilder>,
 780        slash_commands: Arc<SlashCommandWorkingSet>,
 781        project: Option<Entity<Project>>,
 782        telemetry: Option<Arc<Telemetry>>,
 783        cx: &mut Context<Self>,
 784    ) -> Self {
 785        let id = saved_context.id.clone().unwrap_or_else(ContextId::new);
 786        let mut this = Self::new(
 787            id,
 788            ReplicaId::default(),
 789            language::Capability::ReadWrite,
 790            language_registry,
 791            prompt_builder,
 792            slash_commands,
 793            project,
 794            telemetry,
 795            cx,
 796        );
 797        this.path = Some(path);
 798        this.buffer.update(cx, |buffer, cx| {
 799            buffer.set_text(saved_context.text.as_str(), cx)
 800        });
 801        let operations = saved_context.into_ops(&this.buffer, cx);
 802        this.apply_ops(operations, cx);
 803        this
 804    }
 805
 806    pub fn id(&self) -> &ContextId {
 807        &self.id
 808    }
 809
 810    pub fn replica_id(&self) -> ReplicaId {
 811        self.timestamp.replica_id
 812    }
 813
 814    pub fn version(&self, cx: &App) -> ContextVersion {
 815        ContextVersion {
 816            context: self.version.clone(),
 817            buffer: self.buffer.read(cx).version(),
 818        }
 819    }
 820
 821    pub fn slash_commands(&self) -> &Arc<SlashCommandWorkingSet> {
 822        &self.slash_commands
 823    }
 824
 825    pub fn set_capability(&mut self, capability: language::Capability, cx: &mut Context<Self>) {
 826        self.buffer
 827            .update(cx, |buffer, cx| buffer.set_capability(capability, cx));
 828    }
 829
 830    fn next_timestamp(&mut self) -> clock::Lamport {
 831        let timestamp = self.timestamp.tick();
 832        self.version.observe(timestamp);
 833        timestamp
 834    }
 835
 836    pub fn serialize_ops(
 837        &self,
 838        since: &ContextVersion,
 839        cx: &App,
 840    ) -> Task<Vec<proto::ContextOperation>> {
 841        let buffer_ops = self
 842            .buffer
 843            .read(cx)
 844            .serialize_ops(Some(since.buffer.clone()), cx);
 845
 846        let mut context_ops = self
 847            .operations
 848            .iter()
 849            .filter(|op| !since.context.observed(op.timestamp()))
 850            .cloned()
 851            .collect::<Vec<_>>();
 852        context_ops.extend(self.pending_ops.iter().cloned());
 853
 854        cx.background_spawn(async move {
 855            let buffer_ops = buffer_ops.await;
 856            context_ops.sort_unstable_by_key(|op| op.timestamp());
 857            buffer_ops
 858                .into_iter()
 859                .map(|op| proto::ContextOperation {
 860                    variant: Some(proto::context_operation::Variant::BufferOperation(
 861                        proto::context_operation::BufferOperation {
 862                            operation: Some(op),
 863                        },
 864                    )),
 865                })
 866                .chain(context_ops.into_iter().map(|op| op.to_proto()))
 867                .collect()
 868        })
 869    }
 870
 871    pub fn apply_ops(
 872        &mut self,
 873        ops: impl IntoIterator<Item = ContextOperation>,
 874        cx: &mut Context<Self>,
 875    ) {
 876        let mut buffer_ops = Vec::new();
 877        for op in ops {
 878            match op {
 879                ContextOperation::BufferOperation(buffer_op) => buffer_ops.push(buffer_op),
 880                op @ _ => self.pending_ops.push(op),
 881            }
 882        }
 883        self.buffer
 884            .update(cx, |buffer, cx| buffer.apply_ops(buffer_ops, cx));
 885        self.flush_ops(cx);
 886    }
 887
 888    fn flush_ops(&mut self, cx: &mut Context<AssistantContext>) {
 889        let mut changed_messages = HashSet::default();
 890        let mut summary_changed = false;
 891
 892        self.pending_ops.sort_unstable_by_key(|op| op.timestamp());
 893        for op in mem::take(&mut self.pending_ops) {
 894            if !self.can_apply_op(&op, cx) {
 895                self.pending_ops.push(op);
 896                continue;
 897            }
 898
 899            let timestamp = op.timestamp();
 900            match op.clone() {
 901                ContextOperation::InsertMessage {
 902                    anchor, metadata, ..
 903                } => {
 904                    if self.messages_metadata.contains_key(&anchor.id) {
 905                        // We already applied this operation.
 906                    } else {
 907                        changed_messages.insert(anchor.id);
 908                        self.insert_message(anchor, metadata, cx);
 909                    }
 910                }
 911                ContextOperation::UpdateMessage {
 912                    message_id,
 913                    metadata: new_metadata,
 914                    ..
 915                } => {
 916                    let metadata = self.messages_metadata.get_mut(&message_id).unwrap();
 917                    if new_metadata.timestamp > metadata.timestamp {
 918                        *metadata = new_metadata;
 919                        changed_messages.insert(message_id);
 920                    }
 921                }
 922                ContextOperation::UpdateSummary {
 923                    summary: new_summary,
 924                    ..
 925                } => {
 926                    if self
 927                        .summary
 928                        .as_ref()
 929                        .map_or(true, |summary| new_summary.timestamp > summary.timestamp)
 930                    {
 931                        self.summary = Some(new_summary);
 932                        summary_changed = true;
 933                    }
 934                }
 935                ContextOperation::SlashCommandStarted {
 936                    id,
 937                    output_range,
 938                    name,
 939                    ..
 940                } => {
 941                    self.invoked_slash_commands.insert(
 942                        id,
 943                        InvokedSlashCommand {
 944                            name: name.into(),
 945                            range: output_range,
 946                            run_commands_in_ranges: Vec::new(),
 947                            status: InvokedSlashCommandStatus::Running(Task::ready(())),
 948                            transaction: None,
 949                            timestamp: id.0,
 950                        },
 951                    );
 952                    cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id: id });
 953                }
 954                ContextOperation::SlashCommandOutputSectionAdded { section, .. } => {
 955                    let buffer = self.buffer.read(cx);
 956                    if let Err(ix) = self
 957                        .slash_command_output_sections
 958                        .binary_search_by(|probe| probe.range.cmp(&section.range, buffer))
 959                    {
 960                        self.slash_command_output_sections
 961                            .insert(ix, section.clone());
 962                        cx.emit(ContextEvent::SlashCommandOutputSectionAdded { section });
 963                    }
 964                }
 965                ContextOperation::SlashCommandFinished {
 966                    id,
 967                    error_message,
 968                    timestamp,
 969                    ..
 970                } => {
 971                    if let Some(slash_command) = self.invoked_slash_commands.get_mut(&id) {
 972                        if timestamp > slash_command.timestamp {
 973                            slash_command.timestamp = timestamp;
 974                            match error_message {
 975                                Some(message) => {
 976                                    slash_command.status =
 977                                        InvokedSlashCommandStatus::Error(message.into());
 978                                }
 979                                None => {
 980                                    slash_command.status = InvokedSlashCommandStatus::Finished;
 981                                }
 982                            }
 983                            cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id: id });
 984                        }
 985                    }
 986                }
 987                ContextOperation::BufferOperation(_) => unreachable!(),
 988            }
 989
 990            self.version.observe(timestamp);
 991            self.timestamp.observe(timestamp);
 992            self.operations.push(op);
 993        }
 994
 995        if !changed_messages.is_empty() {
 996            self.message_roles_updated(changed_messages, cx);
 997            cx.emit(ContextEvent::MessagesEdited);
 998            cx.notify();
 999        }
1000
1001        if summary_changed {
1002            cx.emit(ContextEvent::SummaryChanged);
1003            cx.notify();
1004        }
1005    }
1006
1007    fn can_apply_op(&self, op: &ContextOperation, cx: &App) -> bool {
1008        if !self.version.observed_all(op.version()) {
1009            return false;
1010        }
1011
1012        match op {
1013            ContextOperation::InsertMessage { anchor, .. } => self
1014                .buffer
1015                .read(cx)
1016                .version
1017                .observed(anchor.start.timestamp),
1018            ContextOperation::UpdateMessage { message_id, .. } => {
1019                self.messages_metadata.contains_key(message_id)
1020            }
1021            ContextOperation::UpdateSummary { .. } => true,
1022            ContextOperation::SlashCommandStarted { output_range, .. } => {
1023                self.has_received_operations_for_anchor_range(output_range.clone(), cx)
1024            }
1025            ContextOperation::SlashCommandOutputSectionAdded { section, .. } => {
1026                self.has_received_operations_for_anchor_range(section.range.clone(), cx)
1027            }
1028            ContextOperation::SlashCommandFinished { .. } => true,
1029            ContextOperation::BufferOperation(_) => {
1030                panic!("buffer operations should always be applied")
1031            }
1032        }
1033    }
1034
1035    fn has_received_operations_for_anchor_range(
1036        &self,
1037        range: Range<text::Anchor>,
1038        cx: &App,
1039    ) -> bool {
1040        let version = &self.buffer.read(cx).version;
1041        let observed_start = range.start == language::Anchor::MIN
1042            || range.start == language::Anchor::MAX
1043            || version.observed(range.start.timestamp);
1044        let observed_end = range.end == language::Anchor::MIN
1045            || range.end == language::Anchor::MAX
1046            || version.observed(range.end.timestamp);
1047        observed_start && observed_end
1048    }
1049
1050    fn push_op(&mut self, op: ContextOperation, cx: &mut Context<Self>) {
1051        self.operations.push(op.clone());
1052        cx.emit(ContextEvent::Operation(op));
1053    }
1054
1055    pub fn buffer(&self) -> &Entity<Buffer> {
1056        &self.buffer
1057    }
1058
1059    pub fn language_registry(&self) -> Arc<LanguageRegistry> {
1060        self.language_registry.clone()
1061    }
1062
1063    pub fn project(&self) -> Option<Entity<Project>> {
1064        self.project.clone()
1065    }
1066
1067    pub fn prompt_builder(&self) -> Arc<PromptBuilder> {
1068        self.prompt_builder.clone()
1069    }
1070
1071    pub fn path(&self) -> Option<&Path> {
1072        self.path.as_deref()
1073    }
1074
1075    pub fn summary(&self) -> Option<&ContextSummary> {
1076        self.summary.as_ref()
1077    }
1078
1079    pub fn patch_containing(&self, position: Point, cx: &App) -> Option<&AssistantPatch> {
1080        let buffer = self.buffer.read(cx);
1081        let index = self.patches.binary_search_by(|patch| {
1082            let patch_range = patch.range.to_point(&buffer);
1083            if position < patch_range.start {
1084                Ordering::Greater
1085            } else if position > patch_range.end {
1086                Ordering::Less
1087            } else {
1088                Ordering::Equal
1089            }
1090        });
1091        if let Ok(ix) = index {
1092            Some(&self.patches[ix])
1093        } else {
1094            None
1095        }
1096    }
1097
1098    pub fn patch_ranges(&self) -> impl Iterator<Item = Range<language::Anchor>> + '_ {
1099        self.patches.iter().map(|patch| patch.range.clone())
1100    }
1101
1102    pub fn patch_for_range(
1103        &self,
1104        range: &Range<language::Anchor>,
1105        cx: &App,
1106    ) -> Option<&AssistantPatch> {
1107        let buffer = self.buffer.read(cx);
1108        let index = self.patch_index_for_range(range, buffer).ok()?;
1109        Some(&self.patches[index])
1110    }
1111
1112    fn patch_index_for_range(
1113        &self,
1114        tagged_range: &Range<text::Anchor>,
1115        buffer: &text::BufferSnapshot,
1116    ) -> Result<usize, usize> {
1117        self.patches
1118            .binary_search_by(|probe| probe.range.cmp(&tagged_range, buffer))
1119    }
1120
1121    pub fn parsed_slash_commands(&self) -> &[ParsedSlashCommand] {
1122        &self.parsed_slash_commands
1123    }
1124
1125    pub fn invoked_slash_command(
1126        &self,
1127        command_id: &InvokedSlashCommandId,
1128    ) -> Option<&InvokedSlashCommand> {
1129        self.invoked_slash_commands.get(command_id)
1130    }
1131
1132    pub fn slash_command_output_sections(&self) -> &[SlashCommandOutputSection<language::Anchor>] {
1133        &self.slash_command_output_sections
1134    }
1135
1136    pub fn contains_files(&self, cx: &App) -> bool {
1137        let buffer = self.buffer.read(cx);
1138        self.slash_command_output_sections.iter().any(|section| {
1139            section.is_valid(buffer)
1140                && section
1141                    .metadata
1142                    .as_ref()
1143                    .and_then(|metadata| {
1144                        serde_json::from_value::<FileCommandMetadata>(metadata.clone()).ok()
1145                    })
1146                    .is_some()
1147        })
1148    }
1149
1150    fn set_language(&mut self, cx: &mut Context<Self>) {
1151        let markdown = self.language_registry.language_for_name("Markdown");
1152        cx.spawn(|this, mut cx| async move {
1153            let markdown = markdown.await?;
1154            this.update(&mut cx, |this, cx| {
1155                this.buffer
1156                    .update(cx, |buffer, cx| buffer.set_language(Some(markdown), cx));
1157            })
1158        })
1159        .detach_and_log_err(cx);
1160    }
1161
1162    fn handle_buffer_event(
1163        &mut self,
1164        _: Entity<Buffer>,
1165        event: &language::BufferEvent,
1166        cx: &mut Context<Self>,
1167    ) {
1168        match event {
1169            language::BufferEvent::Operation {
1170                operation,
1171                is_local: true,
1172            } => cx.emit(ContextEvent::Operation(ContextOperation::BufferOperation(
1173                operation.clone(),
1174            ))),
1175            language::BufferEvent::Edited => {
1176                self.count_remaining_tokens(cx);
1177                self.reparse(cx);
1178                cx.emit(ContextEvent::MessagesEdited);
1179            }
1180            _ => {}
1181        }
1182    }
1183
1184    pub fn token_count(&self) -> Option<usize> {
1185        self.token_count
1186    }
1187
1188    pub(crate) fn count_remaining_tokens(&mut self, cx: &mut Context<Self>) {
1189        // Assume it will be a Chat request, even though that takes fewer tokens (and risks going over the limit),
1190        // because otherwise you see in the UI that your empty message has a bunch of tokens already used.
1191        let request = self.to_completion_request(RequestType::Chat, cx);
1192        let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else {
1193            return;
1194        };
1195        let debounce = self.token_count.is_some();
1196        self.pending_token_count = cx.spawn(|this, mut cx| {
1197            async move {
1198                if debounce {
1199                    cx.background_executor()
1200                        .timer(Duration::from_millis(200))
1201                        .await;
1202                }
1203
1204                let token_count = cx.update(|cx| model.count_tokens(request, cx))?.await?;
1205                this.update(&mut cx, |this, cx| {
1206                    this.token_count = Some(token_count);
1207                    this.start_cache_warming(&model, cx);
1208                    cx.notify()
1209                })
1210            }
1211            .log_err()
1212        });
1213    }
1214
1215    pub fn mark_cache_anchors(
1216        &mut self,
1217        cache_configuration: &Option<LanguageModelCacheConfiguration>,
1218        speculative: bool,
1219        cx: &mut Context<Self>,
1220    ) -> bool {
1221        let cache_configuration =
1222            cache_configuration
1223                .as_ref()
1224                .unwrap_or(&LanguageModelCacheConfiguration {
1225                    max_cache_anchors: 0,
1226                    should_speculate: false,
1227                    min_total_token: 0,
1228                });
1229
1230        let messages: Vec<Message> = self.messages(cx).collect();
1231
1232        let mut sorted_messages = messages.clone();
1233        if speculative {
1234            // Avoid caching the last message if this is a speculative cache fetch as
1235            // it's likely to change.
1236            sorted_messages.pop();
1237        }
1238        sorted_messages.retain(|m| m.role == Role::User);
1239        sorted_messages.sort_by(|a, b| b.offset_range.len().cmp(&a.offset_range.len()));
1240
1241        let cache_anchors = if self.token_count.unwrap_or(0) < cache_configuration.min_total_token {
1242            // If we have't hit the minimum threshold to enable caching, don't cache anything.
1243            0
1244        } else {
1245            // Save 1 anchor for the inline assistant to use.
1246            max(cache_configuration.max_cache_anchors, 1) - 1
1247        };
1248        sorted_messages.truncate(cache_anchors);
1249
1250        let anchors: HashSet<MessageId> = sorted_messages
1251            .into_iter()
1252            .map(|message| message.id)
1253            .collect();
1254
1255        let buffer = self.buffer.read(cx).snapshot();
1256        let invalidated_caches: HashSet<MessageId> = messages
1257            .iter()
1258            .scan(false, |encountered_invalid, message| {
1259                let message_id = message.id;
1260                let is_invalid = self
1261                    .messages_metadata
1262                    .get(&message_id)
1263                    .map_or(true, |metadata| {
1264                        !metadata.is_cache_valid(&buffer, &message.offset_range)
1265                            || *encountered_invalid
1266                    });
1267                *encountered_invalid |= is_invalid;
1268                Some(if is_invalid { Some(message_id) } else { None })
1269            })
1270            .flatten()
1271            .collect();
1272
1273        let last_anchor = messages.iter().rev().find_map(|message| {
1274            if anchors.contains(&message.id) {
1275                Some(message.id)
1276            } else {
1277                None
1278            }
1279        });
1280
1281        let mut new_anchor_needs_caching = false;
1282        let current_version = &buffer.version;
1283        // If we have no anchors, mark all messages as not being cached.
1284        let mut hit_last_anchor = last_anchor.is_none();
1285
1286        for message in messages.iter() {
1287            if hit_last_anchor {
1288                self.update_metadata(message.id, cx, |metadata| metadata.cache = None);
1289                continue;
1290            }
1291
1292            if let Some(last_anchor) = last_anchor {
1293                if message.id == last_anchor {
1294                    hit_last_anchor = true;
1295                }
1296            }
1297
1298            new_anchor_needs_caching = new_anchor_needs_caching
1299                || (invalidated_caches.contains(&message.id) && anchors.contains(&message.id));
1300
1301            self.update_metadata(message.id, cx, |metadata| {
1302                let cache_status = if invalidated_caches.contains(&message.id) {
1303                    CacheStatus::Pending
1304                } else {
1305                    metadata
1306                        .cache
1307                        .as_ref()
1308                        .map_or(CacheStatus::Pending, |cm| cm.status.clone())
1309                };
1310                metadata.cache = Some(MessageCacheMetadata {
1311                    is_anchor: anchors.contains(&message.id),
1312                    is_final_anchor: hit_last_anchor,
1313                    status: cache_status,
1314                    cached_at: current_version.clone(),
1315                });
1316            });
1317        }
1318        new_anchor_needs_caching
1319    }
1320
1321    fn start_cache_warming(&mut self, model: &Arc<dyn LanguageModel>, cx: &mut Context<Self>) {
1322        let cache_configuration = model.cache_configuration();
1323
1324        if !self.mark_cache_anchors(&cache_configuration, true, cx) {
1325            return;
1326        }
1327        if !self.pending_completions.is_empty() {
1328            return;
1329        }
1330        if let Some(cache_configuration) = cache_configuration {
1331            if !cache_configuration.should_speculate {
1332                return;
1333            }
1334        }
1335
1336        let request = {
1337            let mut req = self.to_completion_request(RequestType::Chat, cx);
1338            // Skip the last message because it's likely to change and
1339            // therefore would be a waste to cache.
1340            req.messages.pop();
1341            req.messages.push(LanguageModelRequestMessage {
1342                role: Role::User,
1343                content: vec!["Respond only with OK, nothing else.".into()],
1344                cache: false,
1345            });
1346            req
1347        };
1348
1349        let model = Arc::clone(model);
1350        self.pending_cache_warming_task = cx.spawn(|this, mut cx| {
1351            async move {
1352                match model.stream_completion(request, &cx).await {
1353                    Ok(mut stream) => {
1354                        stream.next().await;
1355                        log::info!("Cache warming completed successfully");
1356                    }
1357                    Err(e) => {
1358                        log::warn!("Cache warming failed: {}", e);
1359                    }
1360                };
1361                this.update(&mut cx, |this, cx| {
1362                    this.update_cache_status_for_completion(cx);
1363                })
1364                .ok();
1365                anyhow::Ok(())
1366            }
1367            .log_err()
1368        });
1369    }
1370
1371    pub fn update_cache_status_for_completion(&mut self, cx: &mut Context<Self>) {
1372        let cached_message_ids: Vec<MessageId> = self
1373            .messages_metadata
1374            .iter()
1375            .filter_map(|(message_id, metadata)| {
1376                metadata.cache.as_ref().and_then(|cache| {
1377                    if cache.status == CacheStatus::Pending {
1378                        Some(*message_id)
1379                    } else {
1380                        None
1381                    }
1382                })
1383            })
1384            .collect();
1385
1386        for message_id in cached_message_ids {
1387            self.update_metadata(message_id, cx, |metadata| {
1388                if let Some(cache) = &mut metadata.cache {
1389                    cache.status = CacheStatus::Cached;
1390                }
1391            });
1392        }
1393        cx.notify();
1394    }
1395
1396    pub fn reparse(&mut self, cx: &mut Context<Self>) {
1397        let buffer = self.buffer.read(cx).text_snapshot();
1398        let mut row_ranges = self
1399            .edits_since_last_parse
1400            .consume()
1401            .into_iter()
1402            .map(|edit| {
1403                let start_row = buffer.offset_to_point(edit.new.start).row;
1404                let end_row = buffer.offset_to_point(edit.new.end).row + 1;
1405                start_row..end_row
1406            })
1407            .peekable();
1408
1409        let mut removed_parsed_slash_command_ranges = Vec::new();
1410        let mut updated_parsed_slash_commands = Vec::new();
1411        let mut removed_patches = Vec::new();
1412        let mut updated_patches = Vec::new();
1413        while let Some(mut row_range) = row_ranges.next() {
1414            while let Some(next_row_range) = row_ranges.peek() {
1415                if row_range.end >= next_row_range.start {
1416                    row_range.end = next_row_range.end;
1417                    row_ranges.next();
1418                } else {
1419                    break;
1420                }
1421            }
1422
1423            let start = buffer.anchor_before(Point::new(row_range.start, 0));
1424            let end = buffer.anchor_after(Point::new(
1425                row_range.end - 1,
1426                buffer.line_len(row_range.end - 1),
1427            ));
1428
1429            self.reparse_slash_commands_in_range(
1430                start..end,
1431                &buffer,
1432                &mut updated_parsed_slash_commands,
1433                &mut removed_parsed_slash_command_ranges,
1434                cx,
1435            );
1436            self.invalidate_pending_slash_commands(&buffer, cx);
1437            self.reparse_patches_in_range(
1438                start..end,
1439                &buffer,
1440                &mut updated_patches,
1441                &mut removed_patches,
1442                cx,
1443            );
1444        }
1445
1446        if !updated_parsed_slash_commands.is_empty()
1447            || !removed_parsed_slash_command_ranges.is_empty()
1448        {
1449            cx.emit(ContextEvent::ParsedSlashCommandsUpdated {
1450                removed: removed_parsed_slash_command_ranges,
1451                updated: updated_parsed_slash_commands,
1452            });
1453        }
1454
1455        if !updated_patches.is_empty() || !removed_patches.is_empty() {
1456            cx.emit(ContextEvent::PatchesUpdated {
1457                removed: removed_patches,
1458                updated: updated_patches,
1459            });
1460        }
1461    }
1462
1463    fn reparse_slash_commands_in_range(
1464        &mut self,
1465        range: Range<text::Anchor>,
1466        buffer: &BufferSnapshot,
1467        updated: &mut Vec<ParsedSlashCommand>,
1468        removed: &mut Vec<Range<text::Anchor>>,
1469        cx: &App,
1470    ) {
1471        let old_range = self.pending_command_indices_for_range(range.clone(), cx);
1472
1473        let mut new_commands = Vec::new();
1474        let mut lines = buffer.text_for_range(range).lines();
1475        let mut offset = lines.offset();
1476        while let Some(line) = lines.next() {
1477            if let Some(command_line) = SlashCommandLine::parse(line) {
1478                let name = &line[command_line.name.clone()];
1479                let arguments = command_line
1480                    .arguments
1481                    .iter()
1482                    .filter_map(|argument_range| {
1483                        if argument_range.is_empty() {
1484                            None
1485                        } else {
1486                            line.get(argument_range.clone())
1487                        }
1488                    })
1489                    .map(ToOwned::to_owned)
1490                    .collect::<SmallVec<_>>();
1491                if let Some(command) = self.slash_commands.command(name, cx) {
1492                    if !command.requires_argument() || !arguments.is_empty() {
1493                        let start_ix = offset + command_line.name.start - 1;
1494                        let end_ix = offset
1495                            + command_line
1496                                .arguments
1497                                .last()
1498                                .map_or(command_line.name.end, |argument| argument.end);
1499                        let source_range =
1500                            buffer.anchor_after(start_ix)..buffer.anchor_after(end_ix);
1501                        let pending_command = ParsedSlashCommand {
1502                            name: name.to_string(),
1503                            arguments,
1504                            source_range,
1505                            status: PendingSlashCommandStatus::Idle,
1506                        };
1507                        updated.push(pending_command.clone());
1508                        new_commands.push(pending_command);
1509                    }
1510                }
1511            }
1512
1513            offset = lines.offset();
1514        }
1515
1516        let removed_commands = self.parsed_slash_commands.splice(old_range, new_commands);
1517        removed.extend(removed_commands.map(|command| command.source_range));
1518    }
1519
1520    fn invalidate_pending_slash_commands(
1521        &mut self,
1522        buffer: &BufferSnapshot,
1523        cx: &mut Context<Self>,
1524    ) {
1525        let mut invalidated_command_ids = Vec::new();
1526        for (&command_id, command) in self.invoked_slash_commands.iter_mut() {
1527            if !matches!(command.status, InvokedSlashCommandStatus::Finished)
1528                && (!command.range.start.is_valid(buffer) || !command.range.end.is_valid(buffer))
1529            {
1530                command.status = InvokedSlashCommandStatus::Finished;
1531                cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id });
1532                invalidated_command_ids.push(command_id);
1533            }
1534        }
1535
1536        for command_id in invalidated_command_ids {
1537            let version = self.version.clone();
1538            let timestamp = self.next_timestamp();
1539            self.push_op(
1540                ContextOperation::SlashCommandFinished {
1541                    id: command_id,
1542                    timestamp,
1543                    error_message: None,
1544                    version: version.clone(),
1545                },
1546                cx,
1547            );
1548        }
1549    }
1550
1551    fn reparse_patches_in_range(
1552        &mut self,
1553        range: Range<text::Anchor>,
1554        buffer: &BufferSnapshot,
1555        updated: &mut Vec<Range<text::Anchor>>,
1556        removed: &mut Vec<Range<text::Anchor>>,
1557        cx: &mut Context<Self>,
1558    ) {
1559        // Rebuild the XML tags in the edited range.
1560        let intersecting_tags_range =
1561            self.indices_intersecting_buffer_range(&self.xml_tags, range.clone(), cx);
1562        let new_tags = self.parse_xml_tags_in_range(buffer, range.clone(), cx);
1563        self.xml_tags
1564            .splice(intersecting_tags_range.clone(), new_tags);
1565
1566        // Find which patches intersect the changed range.
1567        let intersecting_patches_range =
1568            self.indices_intersecting_buffer_range(&self.patches, range.clone(), cx);
1569
1570        // Reparse all tags after the last unchanged patch before the change.
1571        let mut tags_start_ix = 0;
1572        if let Some(preceding_unchanged_patch) =
1573            self.patches[..intersecting_patches_range.start].last()
1574        {
1575            tags_start_ix = match self.xml_tags.binary_search_by(|tag| {
1576                tag.range
1577                    .start
1578                    .cmp(&preceding_unchanged_patch.range.end, buffer)
1579                    .then(Ordering::Less)
1580            }) {
1581                Ok(ix) | Err(ix) => ix,
1582            };
1583        }
1584
1585        // Rebuild the patches in the range.
1586        let new_patches = self.parse_patches(tags_start_ix, range.end, buffer, cx);
1587        updated.extend(new_patches.iter().map(|patch| patch.range.clone()));
1588        let removed_patches = self.patches.splice(intersecting_patches_range, new_patches);
1589        removed.extend(
1590            removed_patches
1591                .map(|patch| patch.range)
1592                .filter(|range| !updated.contains(&range)),
1593        );
1594    }
1595
1596    fn parse_xml_tags_in_range(
1597        &self,
1598        buffer: &BufferSnapshot,
1599        range: Range<text::Anchor>,
1600        cx: &App,
1601    ) -> Vec<XmlTag> {
1602        let mut messages = self.messages(cx).peekable();
1603
1604        let mut tags = Vec::new();
1605        let mut lines = buffer.text_for_range(range).lines();
1606        let mut offset = lines.offset();
1607
1608        while let Some(line) = lines.next() {
1609            while let Some(message) = messages.peek() {
1610                if offset < message.offset_range.end {
1611                    break;
1612                } else {
1613                    messages.next();
1614                }
1615            }
1616
1617            let is_assistant_message = messages
1618                .peek()
1619                .map_or(false, |message| message.role == Role::Assistant);
1620            if is_assistant_message {
1621                for (start_ix, _) in line.match_indices('<') {
1622                    let mut name_start_ix = start_ix + 1;
1623                    let closing_bracket_ix = line[start_ix..].find('>').map(|i| start_ix + i);
1624                    if let Some(closing_bracket_ix) = closing_bracket_ix {
1625                        let end_ix = closing_bracket_ix + 1;
1626                        let mut is_open_tag = true;
1627                        if line[name_start_ix..closing_bracket_ix].starts_with('/') {
1628                            name_start_ix += 1;
1629                            is_open_tag = false;
1630                        }
1631                        let tag_inner = &line[name_start_ix..closing_bracket_ix];
1632                        let tag_name_len = tag_inner
1633                            .find(|c: char| c.is_whitespace())
1634                            .unwrap_or(tag_inner.len());
1635                        if let Ok(kind) = XmlTagKind::from_str(&tag_inner[..tag_name_len]) {
1636                            tags.push(XmlTag {
1637                                range: buffer.anchor_after(offset + start_ix)
1638                                    ..buffer.anchor_before(offset + end_ix),
1639                                is_open_tag,
1640                                kind,
1641                            });
1642                        };
1643                    }
1644                }
1645            }
1646
1647            offset = lines.offset();
1648        }
1649        tags
1650    }
1651
1652    fn parse_patches(
1653        &mut self,
1654        tags_start_ix: usize,
1655        buffer_end: text::Anchor,
1656        buffer: &BufferSnapshot,
1657        cx: &App,
1658    ) -> Vec<AssistantPatch> {
1659        let mut new_patches = Vec::new();
1660        let mut pending_patch = None;
1661        let mut patch_tag_depth = 0;
1662        let mut tags = self.xml_tags[tags_start_ix..].iter().peekable();
1663        'tags: while let Some(tag) = tags.next() {
1664            if tag.range.start.cmp(&buffer_end, buffer).is_gt() && patch_tag_depth == 0 {
1665                break;
1666            }
1667
1668            if tag.kind == XmlTagKind::Patch && tag.is_open_tag {
1669                patch_tag_depth += 1;
1670                let patch_start = tag.range.start;
1671                let mut edits = Vec::<Result<AssistantEdit>>::new();
1672                let mut patch = AssistantPatch {
1673                    range: patch_start..patch_start,
1674                    title: String::new().into(),
1675                    edits: Default::default(),
1676                    status: crate::AssistantPatchStatus::Pending,
1677                };
1678
1679                while let Some(tag) = tags.next() {
1680                    if tag.kind == XmlTagKind::Patch && !tag.is_open_tag {
1681                        patch_tag_depth -= 1;
1682                        if patch_tag_depth == 0 {
1683                            patch.range.end = tag.range.end;
1684
1685                            // Include the line immediately after this <patch> tag if it's empty.
1686                            let patch_end_offset = patch.range.end.to_offset(buffer);
1687                            let mut patch_end_chars = buffer.chars_at(patch_end_offset);
1688                            if patch_end_chars.next() == Some('\n')
1689                                && patch_end_chars.next().map_or(true, |ch| ch == '\n')
1690                            {
1691                                let messages = self.messages_for_offsets(
1692                                    [patch_end_offset, patch_end_offset + 1],
1693                                    cx,
1694                                );
1695                                if messages.len() == 1 {
1696                                    patch.range.end = buffer.anchor_before(patch_end_offset + 1);
1697                                }
1698                            }
1699
1700                            edits.sort_unstable_by(|a, b| {
1701                                if let (Ok(a), Ok(b)) = (a, b) {
1702                                    a.path.cmp(&b.path)
1703                                } else {
1704                                    Ordering::Equal
1705                                }
1706                            });
1707                            patch.edits = edits.into();
1708                            patch.status = AssistantPatchStatus::Ready;
1709                            new_patches.push(patch);
1710                            continue 'tags;
1711                        }
1712                    }
1713
1714                    if tag.kind == XmlTagKind::Title && tag.is_open_tag {
1715                        let content_start = tag.range.end;
1716                        while let Some(tag) = tags.next() {
1717                            if tag.kind == XmlTagKind::Title && !tag.is_open_tag {
1718                                let content_end = tag.range.start;
1719                                patch.title =
1720                                    trimmed_text_in_range(buffer, content_start..content_end)
1721                                        .into();
1722                                break;
1723                            }
1724                        }
1725                    }
1726
1727                    if tag.kind == XmlTagKind::Edit && tag.is_open_tag {
1728                        let mut path = None;
1729                        let mut old_text = None;
1730                        let mut new_text = None;
1731                        let mut operation = None;
1732                        let mut description = None;
1733
1734                        while let Some(tag) = tags.next() {
1735                            if tag.kind == XmlTagKind::Edit && !tag.is_open_tag {
1736                                edits.push(AssistantEdit::new(
1737                                    path,
1738                                    operation,
1739                                    old_text,
1740                                    new_text,
1741                                    description,
1742                                ));
1743                                break;
1744                            }
1745
1746                            if tag.is_open_tag
1747                                && [
1748                                    XmlTagKind::Path,
1749                                    XmlTagKind::OldText,
1750                                    XmlTagKind::NewText,
1751                                    XmlTagKind::Operation,
1752                                    XmlTagKind::Description,
1753                                ]
1754                                .contains(&tag.kind)
1755                            {
1756                                let kind = tag.kind;
1757                                let content_start = tag.range.end;
1758                                if let Some(tag) = tags.peek() {
1759                                    if tag.kind == kind && !tag.is_open_tag {
1760                                        let tag = tags.next().unwrap();
1761                                        let content_end = tag.range.start;
1762                                        let content = trimmed_text_in_range(
1763                                            buffer,
1764                                            content_start..content_end,
1765                                        );
1766                                        match kind {
1767                                            XmlTagKind::Path => path = Some(content),
1768                                            XmlTagKind::Operation => operation = Some(content),
1769                                            XmlTagKind::OldText => {
1770                                                old_text = Some(content).filter(|s| !s.is_empty())
1771                                            }
1772                                            XmlTagKind::NewText => {
1773                                                new_text = Some(content).filter(|s| !s.is_empty())
1774                                            }
1775                                            XmlTagKind::Description => {
1776                                                description =
1777                                                    Some(content).filter(|s| !s.is_empty())
1778                                            }
1779                                            _ => {}
1780                                        }
1781                                    }
1782                                }
1783                            }
1784                        }
1785                    }
1786                }
1787
1788                patch.edits = edits.into();
1789                pending_patch = Some(patch);
1790            }
1791        }
1792
1793        if let Some(mut pending_patch) = pending_patch {
1794            let patch_start = pending_patch.range.start.to_offset(buffer);
1795            if let Some(message) = self.message_for_offset(patch_start, cx) {
1796                if message.anchor_range.end == text::Anchor::MAX {
1797                    pending_patch.range.end = text::Anchor::MAX;
1798                } else {
1799                    let message_end = buffer.anchor_after(message.offset_range.end - 1);
1800                    pending_patch.range.end = message_end;
1801                }
1802            } else {
1803                pending_patch.range.end = text::Anchor::MAX;
1804            }
1805
1806            new_patches.push(pending_patch);
1807        }
1808
1809        new_patches
1810    }
1811
1812    pub fn pending_command_for_position(
1813        &mut self,
1814        position: language::Anchor,
1815        cx: &mut Context<Self>,
1816    ) -> Option<&mut ParsedSlashCommand> {
1817        let buffer = self.buffer.read(cx);
1818        match self
1819            .parsed_slash_commands
1820            .binary_search_by(|probe| probe.source_range.end.cmp(&position, buffer))
1821        {
1822            Ok(ix) => Some(&mut self.parsed_slash_commands[ix]),
1823            Err(ix) => {
1824                let cmd = self.parsed_slash_commands.get_mut(ix)?;
1825                if position.cmp(&cmd.source_range.start, buffer).is_ge()
1826                    && position.cmp(&cmd.source_range.end, buffer).is_le()
1827                {
1828                    Some(cmd)
1829                } else {
1830                    None
1831                }
1832            }
1833        }
1834    }
1835
1836    pub fn pending_commands_for_range(
1837        &self,
1838        range: Range<language::Anchor>,
1839        cx: &App,
1840    ) -> &[ParsedSlashCommand] {
1841        let range = self.pending_command_indices_for_range(range, cx);
1842        &self.parsed_slash_commands[range]
1843    }
1844
1845    fn pending_command_indices_for_range(
1846        &self,
1847        range: Range<language::Anchor>,
1848        cx: &App,
1849    ) -> Range<usize> {
1850        self.indices_intersecting_buffer_range(&self.parsed_slash_commands, range, cx)
1851    }
1852
1853    fn indices_intersecting_buffer_range<T: ContextAnnotation>(
1854        &self,
1855        all_annotations: &[T],
1856        range: Range<language::Anchor>,
1857        cx: &App,
1858    ) -> Range<usize> {
1859        let buffer = self.buffer.read(cx);
1860        let start_ix = match all_annotations
1861            .binary_search_by(|probe| probe.range().end.cmp(&range.start, &buffer))
1862        {
1863            Ok(ix) | Err(ix) => ix,
1864        };
1865        let end_ix = match all_annotations
1866            .binary_search_by(|probe| probe.range().start.cmp(&range.end, &buffer))
1867        {
1868            Ok(ix) => ix + 1,
1869            Err(ix) => ix,
1870        };
1871        start_ix..end_ix
1872    }
1873
1874    pub fn insert_command_output(
1875        &mut self,
1876        command_source_range: Range<language::Anchor>,
1877        name: &str,
1878        output: Task<SlashCommandResult>,
1879        ensure_trailing_newline: bool,
1880        cx: &mut Context<Self>,
1881    ) {
1882        let version = self.version.clone();
1883        let command_id = InvokedSlashCommandId(self.next_timestamp());
1884
1885        const PENDING_OUTPUT_END_MARKER: &str = "";
1886
1887        let (command_range, command_source_range, insert_position, first_transaction) =
1888            self.buffer.update(cx, |buffer, cx| {
1889                let command_source_range = command_source_range.to_offset(buffer);
1890                let mut insertion = format!("\n{PENDING_OUTPUT_END_MARKER}");
1891                if ensure_trailing_newline {
1892                    insertion.push('\n');
1893                }
1894
1895                buffer.finalize_last_transaction();
1896                buffer.start_transaction();
1897                buffer.edit(
1898                    [(
1899                        command_source_range.end..command_source_range.end,
1900                        insertion,
1901                    )],
1902                    None,
1903                    cx,
1904                );
1905                let first_transaction = buffer.end_transaction(cx).unwrap();
1906                buffer.finalize_last_transaction();
1907
1908                let insert_position = buffer.anchor_after(command_source_range.end + 1);
1909                let command_range = buffer.anchor_after(command_source_range.start)
1910                    ..buffer.anchor_before(
1911                        command_source_range.end + 1 + PENDING_OUTPUT_END_MARKER.len(),
1912                    );
1913                let command_source_range = buffer.anchor_before(command_source_range.start)
1914                    ..buffer.anchor_before(command_source_range.end + 1);
1915                (
1916                    command_range,
1917                    command_source_range,
1918                    insert_position,
1919                    first_transaction,
1920                )
1921            });
1922        self.reparse(cx);
1923
1924        let insert_output_task = cx.spawn(|this, mut cx| async move {
1925            let run_command = async {
1926                let mut stream = output.await?;
1927
1928                struct PendingSection {
1929                    start: language::Anchor,
1930                    icon: IconName,
1931                    label: SharedString,
1932                    metadata: Option<serde_json::Value>,
1933                }
1934
1935                let mut pending_section_stack: Vec<PendingSection> = Vec::new();
1936                let mut last_role: Option<Role> = None;
1937                let mut last_section_range = None;
1938
1939                while let Some(event) = stream.next().await {
1940                    let event = event?;
1941                    this.update(&mut cx, |this, cx| {
1942                        this.buffer.update(cx, |buffer, _cx| {
1943                            buffer.finalize_last_transaction();
1944                            buffer.start_transaction()
1945                        });
1946
1947                        match event {
1948                            SlashCommandEvent::StartMessage {
1949                                role,
1950                                merge_same_roles,
1951                            } => {
1952                                if !merge_same_roles && Some(role) != last_role {
1953                                    let offset = this.buffer.read_with(cx, |buffer, _cx| {
1954                                        insert_position.to_offset(buffer)
1955                                    });
1956                                    this.insert_message_at_offset(
1957                                        offset,
1958                                        role,
1959                                        MessageStatus::Pending,
1960                                        cx,
1961                                    );
1962                                }
1963
1964                                last_role = Some(role);
1965                            }
1966                            SlashCommandEvent::StartSection {
1967                                icon,
1968                                label,
1969                                metadata,
1970                            } => {
1971                                this.buffer.update(cx, |buffer, cx| {
1972                                    let insert_point = insert_position.to_point(buffer);
1973                                    if insert_point.column > 0 {
1974                                        buffer.edit([(insert_point..insert_point, "\n")], None, cx);
1975                                    }
1976
1977                                    pending_section_stack.push(PendingSection {
1978                                        start: buffer.anchor_before(insert_position),
1979                                        icon,
1980                                        label,
1981                                        metadata,
1982                                    });
1983                                });
1984                            }
1985                            SlashCommandEvent::Content(SlashCommandContent::Text {
1986                                text,
1987                                run_commands_in_text,
1988                            }) => {
1989                                let start = this.buffer.read(cx).anchor_before(insert_position);
1990
1991                                this.buffer.update(cx, |buffer, cx| {
1992                                    buffer.edit(
1993                                        [(insert_position..insert_position, text)],
1994                                        None,
1995                                        cx,
1996                                    )
1997                                });
1998
1999                                let end = this.buffer.read(cx).anchor_before(insert_position);
2000                                if run_commands_in_text {
2001                                    if let Some(invoked_slash_command) =
2002                                        this.invoked_slash_commands.get_mut(&command_id)
2003                                    {
2004                                        invoked_slash_command
2005                                            .run_commands_in_ranges
2006                                            .push(start..end);
2007                                    }
2008                                }
2009                            }
2010                            SlashCommandEvent::EndSection => {
2011                                if let Some(pending_section) = pending_section_stack.pop() {
2012                                    let offset_range = (pending_section.start..insert_position)
2013                                        .to_offset(this.buffer.read(cx));
2014                                    if !offset_range.is_empty() {
2015                                        let range = this.buffer.update(cx, |buffer, _cx| {
2016                                            buffer.anchor_after(offset_range.start)
2017                                                ..buffer.anchor_before(offset_range.end)
2018                                        });
2019                                        this.insert_slash_command_output_section(
2020                                            SlashCommandOutputSection {
2021                                                range: range.clone(),
2022                                                icon: pending_section.icon,
2023                                                label: pending_section.label,
2024                                                metadata: pending_section.metadata,
2025                                            },
2026                                            cx,
2027                                        );
2028                                        last_section_range = Some(range);
2029                                    }
2030                                }
2031                            }
2032                        }
2033
2034                        this.buffer.update(cx, |buffer, cx| {
2035                            if let Some(event_transaction) = buffer.end_transaction(cx) {
2036                                buffer.merge_transactions(event_transaction, first_transaction);
2037                            }
2038                        });
2039                    })?;
2040                }
2041
2042                this.update(&mut cx, |this, cx| {
2043                    this.buffer.update(cx, |buffer, cx| {
2044                        buffer.finalize_last_transaction();
2045                        buffer.start_transaction();
2046
2047                        let mut deletions = vec![(command_source_range.to_offset(buffer), "")];
2048                        let insert_position = insert_position.to_offset(buffer);
2049                        let command_range_end = command_range.end.to_offset(buffer);
2050
2051                        if buffer.contains_str_at(insert_position, PENDING_OUTPUT_END_MARKER) {
2052                            deletions.push((
2053                                insert_position..insert_position + PENDING_OUTPUT_END_MARKER.len(),
2054                                "",
2055                            ));
2056                        }
2057
2058                        if ensure_trailing_newline
2059                            && buffer.contains_str_at(command_range_end, "\n")
2060                        {
2061                            let newline_offset = insert_position.saturating_sub(1);
2062                            if buffer.contains_str_at(newline_offset, "\n")
2063                                && last_section_range.map_or(true, |last_section_range| {
2064                                    !last_section_range
2065                                        .to_offset(buffer)
2066                                        .contains(&newline_offset)
2067                                })
2068                            {
2069                                deletions.push((command_range_end..command_range_end + 1, ""));
2070                            }
2071                        }
2072
2073                        buffer.edit(deletions, None, cx);
2074
2075                        if let Some(deletion_transaction) = buffer.end_transaction(cx) {
2076                            buffer.merge_transactions(deletion_transaction, first_transaction);
2077                        }
2078                    });
2079                })?;
2080
2081                debug_assert!(pending_section_stack.is_empty());
2082
2083                anyhow::Ok(())
2084            };
2085
2086            let command_result = run_command.await;
2087
2088            this.update(&mut cx, |this, cx| {
2089                let version = this.version.clone();
2090                let timestamp = this.next_timestamp();
2091                let Some(invoked_slash_command) = this.invoked_slash_commands.get_mut(&command_id)
2092                else {
2093                    return;
2094                };
2095                let mut error_message = None;
2096                match command_result {
2097                    Ok(()) => {
2098                        invoked_slash_command.status = InvokedSlashCommandStatus::Finished;
2099                    }
2100                    Err(error) => {
2101                        let message = error.to_string();
2102                        invoked_slash_command.status =
2103                            InvokedSlashCommandStatus::Error(message.clone().into());
2104                        error_message = Some(message);
2105                    }
2106                }
2107
2108                cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id });
2109                this.push_op(
2110                    ContextOperation::SlashCommandFinished {
2111                        id: command_id,
2112                        timestamp,
2113                        error_message,
2114                        version,
2115                    },
2116                    cx,
2117                );
2118            })
2119            .ok();
2120        });
2121
2122        self.invoked_slash_commands.insert(
2123            command_id,
2124            InvokedSlashCommand {
2125                name: name.to_string().into(),
2126                range: command_range.clone(),
2127                run_commands_in_ranges: Vec::new(),
2128                status: InvokedSlashCommandStatus::Running(insert_output_task),
2129                transaction: Some(first_transaction),
2130                timestamp: command_id.0,
2131            },
2132        );
2133        cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id });
2134        self.push_op(
2135            ContextOperation::SlashCommandStarted {
2136                id: command_id,
2137                output_range: command_range,
2138                name: name.to_string(),
2139                version,
2140            },
2141            cx,
2142        );
2143    }
2144
2145    fn insert_slash_command_output_section(
2146        &mut self,
2147        section: SlashCommandOutputSection<language::Anchor>,
2148        cx: &mut Context<Self>,
2149    ) {
2150        let buffer = self.buffer.read(cx);
2151        let insertion_ix = match self
2152            .slash_command_output_sections
2153            .binary_search_by(|probe| probe.range.cmp(&section.range, buffer))
2154        {
2155            Ok(ix) | Err(ix) => ix,
2156        };
2157        self.slash_command_output_sections
2158            .insert(insertion_ix, section.clone());
2159        cx.emit(ContextEvent::SlashCommandOutputSectionAdded {
2160            section: section.clone(),
2161        });
2162        let version = self.version.clone();
2163        let timestamp = self.next_timestamp();
2164        self.push_op(
2165            ContextOperation::SlashCommandOutputSectionAdded {
2166                timestamp,
2167                section,
2168                version,
2169            },
2170            cx,
2171        );
2172    }
2173
2174    pub fn completion_provider_changed(&mut self, cx: &mut Context<Self>) {
2175        self.count_remaining_tokens(cx);
2176    }
2177
2178    fn get_last_valid_message_id(&self, cx: &Context<Self>) -> Option<MessageId> {
2179        self.message_anchors.iter().rev().find_map(|message| {
2180            message
2181                .start
2182                .is_valid(self.buffer.read(cx))
2183                .then_some(message.id)
2184        })
2185    }
2186
2187    pub fn assist(
2188        &mut self,
2189        request_type: RequestType,
2190        cx: &mut Context<Self>,
2191    ) -> Option<MessageAnchor> {
2192        let model_registry = LanguageModelRegistry::read_global(cx);
2193        let provider = model_registry.active_provider()?;
2194        let model = model_registry.active_model()?;
2195        let last_message_id = self.get_last_valid_message_id(cx)?;
2196
2197        if !provider.is_authenticated(cx) {
2198            log::info!("completion provider has no credentials");
2199            return None;
2200        }
2201        // Compute which messages to cache, including the last one.
2202        self.mark_cache_anchors(&model.cache_configuration(), false, cx);
2203
2204        let request = self.to_completion_request(request_type, cx);
2205
2206        let assistant_message = self
2207            .insert_message_after(last_message_id, Role::Assistant, MessageStatus::Pending, cx)
2208            .unwrap();
2209
2210        // Queue up the user's next reply.
2211        let user_message = self
2212            .insert_message_after(assistant_message.id, Role::User, MessageStatus::Done, cx)
2213            .unwrap();
2214
2215        let pending_completion_id = post_inc(&mut self.completion_count);
2216
2217        let task = cx.spawn({
2218            |this, mut cx| async move {
2219                let stream = model.stream_completion(request, &cx);
2220                let assistant_message_id = assistant_message.id;
2221                let mut response_latency = None;
2222                let stream_completion = async {
2223                    let request_start = Instant::now();
2224                    let mut events = stream.await?;
2225                    let mut stop_reason = StopReason::EndTurn;
2226
2227                    while let Some(event) = events.next().await {
2228                        if response_latency.is_none() {
2229                            response_latency = Some(request_start.elapsed());
2230                        }
2231                        let event = event?;
2232
2233                        this.update(&mut cx, |this, cx| {
2234                            let message_ix = this
2235                                .message_anchors
2236                                .iter()
2237                                .position(|message| message.id == assistant_message_id)?;
2238                            this.buffer.update(cx, |buffer, cx| {
2239                                let message_old_end_offset = this.message_anchors[message_ix + 1..]
2240                                    .iter()
2241                                    .find(|message| message.start.is_valid(buffer))
2242                                    .map_or(buffer.len(), |message| {
2243                                        message.start.to_offset(buffer).saturating_sub(1)
2244                                    });
2245
2246                                match event {
2247                                    LanguageModelCompletionEvent::StartMessage { .. } => {}
2248                                    LanguageModelCompletionEvent::Stop(reason) => {
2249                                        stop_reason = reason;
2250                                    }
2251                                    LanguageModelCompletionEvent::Text(chunk) => {
2252                                        buffer.edit(
2253                                            [(
2254                                                message_old_end_offset..message_old_end_offset,
2255                                                chunk,
2256                                            )],
2257                                            None,
2258                                            cx,
2259                                        );
2260                                    }
2261                                    LanguageModelCompletionEvent::ToolUse(_) => {}
2262                                }
2263                            });
2264
2265                            cx.emit(ContextEvent::StreamedCompletion);
2266
2267                            Some(())
2268                        })?;
2269                        smol::future::yield_now().await;
2270                    }
2271                    this.update(&mut cx, |this, cx| {
2272                        this.pending_completions
2273                            .retain(|completion| completion.id != pending_completion_id);
2274                        this.summarize(false, cx);
2275                        this.update_cache_status_for_completion(cx);
2276                    })?;
2277
2278                    anyhow::Ok(stop_reason)
2279                };
2280
2281                let result = stream_completion.await;
2282
2283                this.update(&mut cx, |this, cx| {
2284                    let error_message = if let Some(error) = result.as_ref().err() {
2285                        if error.is::<PaymentRequiredError>() {
2286                            cx.emit(ContextEvent::ShowPaymentRequiredError);
2287                            this.update_metadata(assistant_message_id, cx, |metadata| {
2288                                metadata.status = MessageStatus::Canceled;
2289                            });
2290                            Some(error.to_string())
2291                        } else if error.is::<MaxMonthlySpendReachedError>() {
2292                            cx.emit(ContextEvent::ShowMaxMonthlySpendReachedError);
2293                            this.update_metadata(assistant_message_id, cx, |metadata| {
2294                                metadata.status = MessageStatus::Canceled;
2295                            });
2296                            Some(error.to_string())
2297                        } else {
2298                            let error_message = error
2299                                .chain()
2300                                .map(|err| err.to_string())
2301                                .collect::<Vec<_>>()
2302                                .join("\n");
2303                            cx.emit(ContextEvent::ShowAssistError(SharedString::from(
2304                                error_message.clone(),
2305                            )));
2306                            this.update_metadata(assistant_message_id, cx, |metadata| {
2307                                metadata.status =
2308                                    MessageStatus::Error(SharedString::from(error_message.clone()));
2309                            });
2310                            Some(error_message)
2311                        }
2312                    } else {
2313                        this.update_metadata(assistant_message_id, cx, |metadata| {
2314                            metadata.status = MessageStatus::Done;
2315                        });
2316                        None
2317                    };
2318
2319                    let language_name = this
2320                        .buffer
2321                        .read(cx)
2322                        .language()
2323                        .map(|language| language.name());
2324                    report_assistant_event(
2325                        AssistantEvent {
2326                            conversation_id: Some(this.id.0.clone()),
2327                            kind: AssistantKind::Panel,
2328                            phase: AssistantPhase::Response,
2329                            message_id: None,
2330                            model: model.telemetry_id(),
2331                            model_provider: model.provider_id().to_string(),
2332                            response_latency,
2333                            error_message,
2334                            language_name: language_name.map(|name| name.to_proto()),
2335                        },
2336                        this.telemetry.clone(),
2337                        cx.http_client(),
2338                        model.api_key(cx),
2339                        cx.background_executor(),
2340                    );
2341
2342                    if let Ok(stop_reason) = result {
2343                        match stop_reason {
2344                            StopReason::ToolUse => {}
2345                            StopReason::EndTurn => {}
2346                            StopReason::MaxTokens => {}
2347                        }
2348                    }
2349                })
2350                .ok();
2351            }
2352        });
2353
2354        self.pending_completions.push(PendingCompletion {
2355            id: pending_completion_id,
2356            assistant_message_id: assistant_message.id,
2357            _task: task,
2358        });
2359
2360        Some(user_message)
2361    }
2362
2363    pub fn to_completion_request(
2364        &self,
2365        request_type: RequestType,
2366        cx: &App,
2367    ) -> LanguageModelRequest {
2368        let buffer = self.buffer.read(cx);
2369
2370        let mut contents = self.contents(cx).peekable();
2371
2372        fn collect_text_content(buffer: &Buffer, range: Range<usize>) -> Option<String> {
2373            let text: String = buffer.text_for_range(range.clone()).collect();
2374            if text.trim().is_empty() {
2375                None
2376            } else {
2377                Some(text)
2378            }
2379        }
2380
2381        let mut completion_request = LanguageModelRequest {
2382            messages: Vec::new(),
2383            tools: Vec::new(),
2384            stop: Vec::new(),
2385            temperature: None,
2386        };
2387        for message in self.messages(cx) {
2388            if message.status != MessageStatus::Done {
2389                continue;
2390            }
2391
2392            let mut offset = message.offset_range.start;
2393            let mut request_message = LanguageModelRequestMessage {
2394                role: message.role,
2395                content: Vec::new(),
2396                cache: message
2397                    .cache
2398                    .as_ref()
2399                    .map_or(false, |cache| cache.is_anchor),
2400            };
2401
2402            while let Some(content) = contents.peek() {
2403                if content
2404                    .range()
2405                    .end
2406                    .cmp(&message.anchor_range.end, buffer)
2407                    .is_lt()
2408                {
2409                    let content = contents.next().unwrap();
2410                    let range = content.range().to_offset(buffer);
2411                    request_message.content.extend(
2412                        collect_text_content(buffer, offset..range.start).map(MessageContent::Text),
2413                    );
2414
2415                    match content {
2416                        Content::Image { image, .. } => {
2417                            if let Some(image) = image.clone().now_or_never().flatten() {
2418                                request_message
2419                                    .content
2420                                    .push(language_model::MessageContent::Image(image));
2421                            }
2422                        }
2423                    }
2424
2425                    offset = range.end;
2426                } else {
2427                    break;
2428                }
2429            }
2430
2431            request_message.content.extend(
2432                collect_text_content(buffer, offset..message.offset_range.end)
2433                    .map(MessageContent::Text),
2434            );
2435
2436            completion_request.messages.push(request_message);
2437        }
2438
2439        if let RequestType::SuggestEdits = request_type {
2440            if let Ok(preamble) = self.prompt_builder.generate_suggest_edits_prompt() {
2441                let last_elem_index = completion_request.messages.len();
2442
2443                completion_request
2444                    .messages
2445                    .push(LanguageModelRequestMessage {
2446                        role: Role::User,
2447                        content: vec![MessageContent::Text(preamble)],
2448                        cache: false,
2449                    });
2450
2451                // The preamble message should be sent right before the last actual user message.
2452                completion_request
2453                    .messages
2454                    .swap(last_elem_index, last_elem_index.saturating_sub(1));
2455            }
2456        }
2457
2458        completion_request
2459    }
2460
2461    pub fn cancel_last_assist(&mut self, cx: &mut Context<Self>) -> bool {
2462        if let Some(pending_completion) = self.pending_completions.pop() {
2463            self.update_metadata(pending_completion.assistant_message_id, cx, |metadata| {
2464                if metadata.status == MessageStatus::Pending {
2465                    metadata.status = MessageStatus::Canceled;
2466                }
2467            });
2468            true
2469        } else {
2470            false
2471        }
2472    }
2473
2474    pub fn cycle_message_roles(&mut self, ids: HashSet<MessageId>, cx: &mut Context<Self>) {
2475        for id in &ids {
2476            if let Some(metadata) = self.messages_metadata.get(id) {
2477                let role = metadata.role.cycle();
2478                self.update_metadata(*id, cx, |metadata| metadata.role = role);
2479            }
2480        }
2481
2482        self.message_roles_updated(ids, cx);
2483    }
2484
2485    fn message_roles_updated(&mut self, ids: HashSet<MessageId>, cx: &mut Context<Self>) {
2486        let mut ranges = Vec::new();
2487        for message in self.messages(cx) {
2488            if ids.contains(&message.id) {
2489                ranges.push(message.anchor_range.clone());
2490            }
2491        }
2492
2493        let buffer = self.buffer.read(cx).text_snapshot();
2494        let mut updated = Vec::new();
2495        let mut removed = Vec::new();
2496        for range in ranges {
2497            self.reparse_patches_in_range(range, &buffer, &mut updated, &mut removed, cx);
2498        }
2499
2500        if !updated.is_empty() || !removed.is_empty() {
2501            cx.emit(ContextEvent::PatchesUpdated { removed, updated })
2502        }
2503    }
2504
2505    pub fn update_metadata(
2506        &mut self,
2507        id: MessageId,
2508        cx: &mut Context<Self>,
2509        f: impl FnOnce(&mut MessageMetadata),
2510    ) {
2511        let version = self.version.clone();
2512        let timestamp = self.next_timestamp();
2513        if let Some(metadata) = self.messages_metadata.get_mut(&id) {
2514            f(metadata);
2515            metadata.timestamp = timestamp;
2516            let operation = ContextOperation::UpdateMessage {
2517                message_id: id,
2518                metadata: metadata.clone(),
2519                version,
2520            };
2521            self.push_op(operation, cx);
2522            cx.emit(ContextEvent::MessagesEdited);
2523            cx.notify();
2524        }
2525    }
2526
2527    pub fn insert_message_after(
2528        &mut self,
2529        message_id: MessageId,
2530        role: Role,
2531        status: MessageStatus,
2532        cx: &mut Context<Self>,
2533    ) -> Option<MessageAnchor> {
2534        if let Some(prev_message_ix) = self
2535            .message_anchors
2536            .iter()
2537            .position(|message| message.id == message_id)
2538        {
2539            // Find the next valid message after the one we were given.
2540            let mut next_message_ix = prev_message_ix + 1;
2541            while let Some(next_message) = self.message_anchors.get(next_message_ix) {
2542                if next_message.start.is_valid(self.buffer.read(cx)) {
2543                    break;
2544                }
2545                next_message_ix += 1;
2546            }
2547
2548            let buffer = self.buffer.read(cx);
2549            let offset = self
2550                .message_anchors
2551                .get(next_message_ix)
2552                .map_or(buffer.len(), |message| {
2553                    buffer.clip_offset(message.start.to_offset(buffer) - 1, Bias::Left)
2554                });
2555            Some(self.insert_message_at_offset(offset, role, status, cx))
2556        } else {
2557            None
2558        }
2559    }
2560
2561    fn insert_message_at_offset(
2562        &mut self,
2563        offset: usize,
2564        role: Role,
2565        status: MessageStatus,
2566        cx: &mut Context<Self>,
2567    ) -> MessageAnchor {
2568        let start = self.buffer.update(cx, |buffer, cx| {
2569            buffer.edit([(offset..offset, "\n")], None, cx);
2570            buffer.anchor_before(offset + 1)
2571        });
2572
2573        let version = self.version.clone();
2574        let anchor = MessageAnchor {
2575            id: MessageId(self.next_timestamp()),
2576            start,
2577        };
2578        let metadata = MessageMetadata {
2579            role,
2580            status,
2581            timestamp: anchor.id.0,
2582            cache: None,
2583        };
2584        self.insert_message(anchor.clone(), metadata.clone(), cx);
2585        self.push_op(
2586            ContextOperation::InsertMessage {
2587                anchor: anchor.clone(),
2588                metadata,
2589                version,
2590            },
2591            cx,
2592        );
2593        anchor
2594    }
2595
2596    pub fn insert_content(&mut self, content: Content, cx: &mut Context<Self>) {
2597        let buffer = self.buffer.read(cx);
2598        let insertion_ix = match self
2599            .contents
2600            .binary_search_by(|probe| probe.cmp(&content, buffer))
2601        {
2602            Ok(ix) => {
2603                self.contents.remove(ix);
2604                ix
2605            }
2606            Err(ix) => ix,
2607        };
2608        self.contents.insert(insertion_ix, content);
2609        cx.emit(ContextEvent::MessagesEdited);
2610    }
2611
2612    pub fn contents<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator<Item = Content> {
2613        let buffer = self.buffer.read(cx);
2614        self.contents
2615            .iter()
2616            .filter(|content| {
2617                let range = content.range();
2618                range.start.is_valid(buffer) && range.end.is_valid(buffer)
2619            })
2620            .cloned()
2621    }
2622
2623    pub fn split_message(
2624        &mut self,
2625        range: Range<usize>,
2626        cx: &mut Context<Self>,
2627    ) -> (Option<MessageAnchor>, Option<MessageAnchor>) {
2628        let start_message = self.message_for_offset(range.start, cx);
2629        let end_message = self.message_for_offset(range.end, cx);
2630        if let Some((start_message, end_message)) = start_message.zip(end_message) {
2631            // Prevent splitting when range spans multiple messages.
2632            if start_message.id != end_message.id {
2633                return (None, None);
2634            }
2635
2636            let message = start_message;
2637            let role = message.role;
2638            let mut edited_buffer = false;
2639
2640            let mut suffix_start = None;
2641
2642            // TODO: why did this start panicking?
2643            if range.start > message.offset_range.start
2644                && range.end < message.offset_range.end.saturating_sub(1)
2645            {
2646                if self.buffer.read(cx).chars_at(range.end).next() == Some('\n') {
2647                    suffix_start = Some(range.end + 1);
2648                } else if self.buffer.read(cx).reversed_chars_at(range.end).next() == Some('\n') {
2649                    suffix_start = Some(range.end);
2650                }
2651            }
2652
2653            let version = self.version.clone();
2654            let suffix = if let Some(suffix_start) = suffix_start {
2655                MessageAnchor {
2656                    id: MessageId(self.next_timestamp()),
2657                    start: self.buffer.read(cx).anchor_before(suffix_start),
2658                }
2659            } else {
2660                self.buffer.update(cx, |buffer, cx| {
2661                    buffer.edit([(range.end..range.end, "\n")], None, cx);
2662                });
2663                edited_buffer = true;
2664                MessageAnchor {
2665                    id: MessageId(self.next_timestamp()),
2666                    start: self.buffer.read(cx).anchor_before(range.end + 1),
2667                }
2668            };
2669
2670            let suffix_metadata = MessageMetadata {
2671                role,
2672                status: MessageStatus::Done,
2673                timestamp: suffix.id.0,
2674                cache: None,
2675            };
2676            self.insert_message(suffix.clone(), suffix_metadata.clone(), cx);
2677            self.push_op(
2678                ContextOperation::InsertMessage {
2679                    anchor: suffix.clone(),
2680                    metadata: suffix_metadata,
2681                    version,
2682                },
2683                cx,
2684            );
2685
2686            let new_messages =
2687                if range.start == range.end || range.start == message.offset_range.start {
2688                    (None, Some(suffix))
2689                } else {
2690                    let mut prefix_end = None;
2691                    if range.start > message.offset_range.start
2692                        && range.end < message.offset_range.end - 1
2693                    {
2694                        if self.buffer.read(cx).chars_at(range.start).next() == Some('\n') {
2695                            prefix_end = Some(range.start + 1);
2696                        } else if self.buffer.read(cx).reversed_chars_at(range.start).next()
2697                            == Some('\n')
2698                        {
2699                            prefix_end = Some(range.start);
2700                        }
2701                    }
2702
2703                    let version = self.version.clone();
2704                    let selection = if let Some(prefix_end) = prefix_end {
2705                        MessageAnchor {
2706                            id: MessageId(self.next_timestamp()),
2707                            start: self.buffer.read(cx).anchor_before(prefix_end),
2708                        }
2709                    } else {
2710                        self.buffer.update(cx, |buffer, cx| {
2711                            buffer.edit([(range.start..range.start, "\n")], None, cx)
2712                        });
2713                        edited_buffer = true;
2714                        MessageAnchor {
2715                            id: MessageId(self.next_timestamp()),
2716                            start: self.buffer.read(cx).anchor_before(range.end + 1),
2717                        }
2718                    };
2719
2720                    let selection_metadata = MessageMetadata {
2721                        role,
2722                        status: MessageStatus::Done,
2723                        timestamp: selection.id.0,
2724                        cache: None,
2725                    };
2726                    self.insert_message(selection.clone(), selection_metadata.clone(), cx);
2727                    self.push_op(
2728                        ContextOperation::InsertMessage {
2729                            anchor: selection.clone(),
2730                            metadata: selection_metadata,
2731                            version,
2732                        },
2733                        cx,
2734                    );
2735
2736                    (Some(selection), Some(suffix))
2737                };
2738
2739            if !edited_buffer {
2740                cx.emit(ContextEvent::MessagesEdited);
2741            }
2742            new_messages
2743        } else {
2744            (None, None)
2745        }
2746    }
2747
2748    fn insert_message(
2749        &mut self,
2750        new_anchor: MessageAnchor,
2751        new_metadata: MessageMetadata,
2752        cx: &mut Context<Self>,
2753    ) {
2754        cx.emit(ContextEvent::MessagesEdited);
2755
2756        self.messages_metadata.insert(new_anchor.id, new_metadata);
2757
2758        let buffer = self.buffer.read(cx);
2759        let insertion_ix = self
2760            .message_anchors
2761            .iter()
2762            .position(|anchor| {
2763                let comparison = new_anchor.start.cmp(&anchor.start, buffer);
2764                comparison.is_lt() || (comparison.is_eq() && new_anchor.id > anchor.id)
2765            })
2766            .unwrap_or(self.message_anchors.len());
2767        self.message_anchors.insert(insertion_ix, new_anchor);
2768    }
2769
2770    pub fn summarize(&mut self, replace_old: bool, cx: &mut Context<Self>) {
2771        let Some(provider) = LanguageModelRegistry::read_global(cx).active_provider() else {
2772            return;
2773        };
2774        let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else {
2775            return;
2776        };
2777
2778        if replace_old || (self.message_anchors.len() >= 2 && self.summary.is_none()) {
2779            if !provider.is_authenticated(cx) {
2780                return;
2781            }
2782
2783            let mut request = self.to_completion_request(RequestType::Chat, cx);
2784            request.messages.push(LanguageModelRequestMessage {
2785                role: Role::User,
2786                content: vec![
2787                    "Generate a concise 3-7 word title for this conversation, omitting punctuation. Go straight to the title, without any preamble and prefix like `Here's a concise suggestion:...` or `Title:`"
2788                        .into(),
2789                ],
2790                cache: false,
2791            });
2792
2793            self.pending_summary = cx.spawn(|this, mut cx| {
2794                async move {
2795                    let stream = model.stream_completion_text(request, &cx);
2796                    let mut messages = stream.await?;
2797
2798                    let mut replaced = !replace_old;
2799                    while let Some(message) = messages.stream.next().await {
2800                        let text = message?;
2801                        let mut lines = text.lines();
2802                        this.update(&mut cx, |this, cx| {
2803                            let version = this.version.clone();
2804                            let timestamp = this.next_timestamp();
2805                            let summary = this.summary.get_or_insert(ContextSummary::default());
2806                            if !replaced && replace_old {
2807                                summary.text.clear();
2808                                replaced = true;
2809                            }
2810                            summary.text.extend(lines.next());
2811                            summary.timestamp = timestamp;
2812                            let operation = ContextOperation::UpdateSummary {
2813                                summary: summary.clone(),
2814                                version,
2815                            };
2816                            this.push_op(operation, cx);
2817                            cx.emit(ContextEvent::SummaryChanged);
2818                        })?;
2819
2820                        // Stop if the LLM generated multiple lines.
2821                        if lines.next().is_some() {
2822                            break;
2823                        }
2824                    }
2825
2826                    this.update(&mut cx, |this, cx| {
2827                        let version = this.version.clone();
2828                        let timestamp = this.next_timestamp();
2829                        if let Some(summary) = this.summary.as_mut() {
2830                            summary.done = true;
2831                            summary.timestamp = timestamp;
2832                            let operation = ContextOperation::UpdateSummary {
2833                                summary: summary.clone(),
2834                                version,
2835                            };
2836                            this.push_op(operation, cx);
2837                            cx.emit(ContextEvent::SummaryChanged);
2838                        }
2839                    })?;
2840
2841                    anyhow::Ok(())
2842                }
2843                .log_err()
2844            });
2845        }
2846    }
2847
2848    fn message_for_offset(&self, offset: usize, cx: &App) -> Option<Message> {
2849        self.messages_for_offsets([offset], cx).pop()
2850    }
2851
2852    pub fn messages_for_offsets(
2853        &self,
2854        offsets: impl IntoIterator<Item = usize>,
2855        cx: &App,
2856    ) -> Vec<Message> {
2857        let mut result = Vec::new();
2858
2859        let mut messages = self.messages(cx).peekable();
2860        let mut offsets = offsets.into_iter().peekable();
2861        let mut current_message = messages.next();
2862        while let Some(offset) = offsets.next() {
2863            // Locate the message that contains the offset.
2864            while current_message.as_ref().map_or(false, |message| {
2865                !message.offset_range.contains(&offset) && messages.peek().is_some()
2866            }) {
2867                current_message = messages.next();
2868            }
2869            let Some(message) = current_message.as_ref() else {
2870                break;
2871            };
2872
2873            // Skip offsets that are in the same message.
2874            while offsets.peek().map_or(false, |offset| {
2875                message.offset_range.contains(offset) || messages.peek().is_none()
2876            }) {
2877                offsets.next();
2878            }
2879
2880            result.push(message.clone());
2881        }
2882        result
2883    }
2884
2885    fn messages_from_anchors<'a>(
2886        &'a self,
2887        message_anchors: impl Iterator<Item = &'a MessageAnchor> + 'a,
2888        cx: &'a App,
2889    ) -> impl 'a + Iterator<Item = Message> {
2890        let buffer = self.buffer.read(cx);
2891
2892        Self::messages_from_iters(buffer, &self.messages_metadata, message_anchors.enumerate())
2893    }
2894
2895    pub fn messages<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator<Item = Message> {
2896        self.messages_from_anchors(self.message_anchors.iter(), cx)
2897    }
2898
2899    pub fn messages_from_iters<'a>(
2900        buffer: &'a Buffer,
2901        metadata: &'a HashMap<MessageId, MessageMetadata>,
2902        messages: impl Iterator<Item = (usize, &'a MessageAnchor)> + 'a,
2903    ) -> impl 'a + Iterator<Item = Message> {
2904        let mut messages = messages.peekable();
2905
2906        iter::from_fn(move || {
2907            if let Some((start_ix, message_anchor)) = messages.next() {
2908                let metadata = metadata.get(&message_anchor.id)?;
2909
2910                let message_start = message_anchor.start.to_offset(buffer);
2911                let mut message_end = None;
2912                let mut end_ix = start_ix;
2913                while let Some((_, next_message)) = messages.peek() {
2914                    if next_message.start.is_valid(buffer) {
2915                        message_end = Some(next_message.start);
2916                        break;
2917                    } else {
2918                        end_ix += 1;
2919                        messages.next();
2920                    }
2921                }
2922                let message_end_anchor = message_end.unwrap_or(language::Anchor::MAX);
2923                let message_end = message_end_anchor.to_offset(buffer);
2924
2925                return Some(Message {
2926                    index_range: start_ix..end_ix,
2927                    offset_range: message_start..message_end,
2928                    anchor_range: message_anchor.start..message_end_anchor,
2929                    id: message_anchor.id,
2930                    role: metadata.role,
2931                    status: metadata.status.clone(),
2932                    cache: metadata.cache.clone(),
2933                });
2934            }
2935            None
2936        })
2937    }
2938
2939    pub fn save(
2940        &mut self,
2941        debounce: Option<Duration>,
2942        fs: Arc<dyn Fs>,
2943        cx: &mut Context<AssistantContext>,
2944    ) {
2945        if self.replica_id() != ReplicaId::default() {
2946            // Prevent saving a remote context for now.
2947            return;
2948        }
2949
2950        self.pending_save = cx.spawn(|this, mut cx| async move {
2951            if let Some(debounce) = debounce {
2952                cx.background_executor().timer(debounce).await;
2953            }
2954
2955            let (old_path, summary) = this.read_with(&cx, |this, _| {
2956                let path = this.path.clone();
2957                let summary = if let Some(summary) = this.summary.as_ref() {
2958                    if summary.done {
2959                        Some(summary.text.clone())
2960                    } else {
2961                        None
2962                    }
2963                } else {
2964                    None
2965                };
2966                (path, summary)
2967            })?;
2968
2969            if let Some(summary) = summary {
2970                let context = this.read_with(&cx, |this, cx| this.serialize(cx))?;
2971                let mut discriminant = 1;
2972                let mut new_path;
2973                loop {
2974                    new_path = contexts_dir().join(&format!(
2975                        "{} - {}.zed.json",
2976                        summary.trim(),
2977                        discriminant
2978                    ));
2979                    if fs.is_file(&new_path).await {
2980                        discriminant += 1;
2981                    } else {
2982                        break;
2983                    }
2984                }
2985
2986                fs.create_dir(contexts_dir().as_ref()).await?;
2987                fs.atomic_write(new_path.clone(), serde_json::to_string(&context).unwrap())
2988                    .await?;
2989                if let Some(old_path) = old_path {
2990                    if new_path != old_path {
2991                        fs.remove_file(
2992                            &old_path,
2993                            RemoveOptions {
2994                                recursive: false,
2995                                ignore_if_not_exists: true,
2996                            },
2997                        )
2998                        .await?;
2999                    }
3000                }
3001
3002                this.update(&mut cx, |this, _| this.path = Some(new_path))?;
3003            }
3004
3005            Ok(())
3006        });
3007    }
3008
3009    pub fn custom_summary(&mut self, custom_summary: String, cx: &mut Context<Self>) {
3010        let timestamp = self.next_timestamp();
3011        let summary = self.summary.get_or_insert(ContextSummary::default());
3012        summary.timestamp = timestamp;
3013        summary.done = true;
3014        summary.text = custom_summary;
3015        cx.emit(ContextEvent::SummaryChanged);
3016    }
3017}
3018
3019fn trimmed_text_in_range(buffer: &BufferSnapshot, range: Range<text::Anchor>) -> String {
3020    let mut is_start = true;
3021    let mut content = buffer
3022        .text_for_range(range)
3023        .map(|mut chunk| {
3024            if is_start {
3025                chunk = chunk.trim_start_matches('\n');
3026                if !chunk.is_empty() {
3027                    is_start = false;
3028                }
3029            }
3030            chunk
3031        })
3032        .collect::<String>();
3033    content.truncate(content.trim_end().len());
3034    content
3035}
3036
3037#[derive(Debug, Default)]
3038pub struct ContextVersion {
3039    context: clock::Global,
3040    buffer: clock::Global,
3041}
3042
3043impl ContextVersion {
3044    pub fn from_proto(proto: &proto::ContextVersion) -> Self {
3045        Self {
3046            context: language::proto::deserialize_version(&proto.context_version),
3047            buffer: language::proto::deserialize_version(&proto.buffer_version),
3048        }
3049    }
3050
3051    pub fn to_proto(&self, context_id: ContextId) -> proto::ContextVersion {
3052        proto::ContextVersion {
3053            context_id: context_id.to_proto(),
3054            context_version: language::proto::serialize_version(&self.context),
3055            buffer_version: language::proto::serialize_version(&self.buffer),
3056        }
3057    }
3058}
3059
3060#[derive(Debug, Clone)]
3061pub struct ParsedSlashCommand {
3062    pub name: String,
3063    pub arguments: SmallVec<[String; 3]>,
3064    pub status: PendingSlashCommandStatus,
3065    pub source_range: Range<language::Anchor>,
3066}
3067
3068#[derive(Debug)]
3069pub struct InvokedSlashCommand {
3070    pub name: SharedString,
3071    pub range: Range<language::Anchor>,
3072    pub run_commands_in_ranges: Vec<Range<language::Anchor>>,
3073    pub status: InvokedSlashCommandStatus,
3074    pub transaction: Option<language::TransactionId>,
3075    timestamp: clock::Lamport,
3076}
3077
3078#[derive(Debug)]
3079pub enum InvokedSlashCommandStatus {
3080    Running(Task<()>),
3081    Error(SharedString),
3082    Finished,
3083}
3084
3085#[derive(Debug, Clone)]
3086pub enum PendingSlashCommandStatus {
3087    Idle,
3088    Running { _task: Shared<Task<()>> },
3089    Error(String),
3090}
3091
3092#[derive(Debug, Clone)]
3093pub struct PendingToolUse {
3094    pub id: LanguageModelToolUseId,
3095    pub name: String,
3096    pub input: serde_json::Value,
3097    pub status: PendingToolUseStatus,
3098    pub source_range: Range<language::Anchor>,
3099}
3100
3101#[derive(Debug, Clone)]
3102pub enum PendingToolUseStatus {
3103    Idle,
3104    Running { _task: Shared<Task<()>> },
3105    Error(String),
3106}
3107
3108impl PendingToolUseStatus {
3109    pub fn is_idle(&self) -> bool {
3110        matches!(self, PendingToolUseStatus::Idle)
3111    }
3112}
3113
3114#[derive(Serialize, Deserialize)]
3115pub struct SavedMessage {
3116    pub id: MessageId,
3117    pub start: usize,
3118    pub metadata: MessageMetadata,
3119}
3120
3121#[derive(Serialize, Deserialize)]
3122pub struct SavedContext {
3123    pub id: Option<ContextId>,
3124    pub zed: String,
3125    pub version: String,
3126    pub text: String,
3127    pub messages: Vec<SavedMessage>,
3128    pub summary: String,
3129    pub slash_command_output_sections:
3130        Vec<assistant_slash_command::SlashCommandOutputSection<usize>>,
3131}
3132
3133impl SavedContext {
3134    pub const VERSION: &'static str = "0.4.0";
3135
3136    pub fn from_json(json: &str) -> Result<Self> {
3137        let saved_context_json = serde_json::from_str::<serde_json::Value>(json)?;
3138        match saved_context_json
3139            .get("version")
3140            .ok_or_else(|| anyhow!("version not found"))?
3141        {
3142            serde_json::Value::String(version) => match version.as_str() {
3143                SavedContext::VERSION => {
3144                    Ok(serde_json::from_value::<SavedContext>(saved_context_json)?)
3145                }
3146                SavedContextV0_3_0::VERSION => {
3147                    let saved_context =
3148                        serde_json::from_value::<SavedContextV0_3_0>(saved_context_json)?;
3149                    Ok(saved_context.upgrade())
3150                }
3151                SavedContextV0_2_0::VERSION => {
3152                    let saved_context =
3153                        serde_json::from_value::<SavedContextV0_2_0>(saved_context_json)?;
3154                    Ok(saved_context.upgrade())
3155                }
3156                SavedContextV0_1_0::VERSION => {
3157                    let saved_context =
3158                        serde_json::from_value::<SavedContextV0_1_0>(saved_context_json)?;
3159                    Ok(saved_context.upgrade())
3160                }
3161                _ => Err(anyhow!("unrecognized saved context version: {}", version)),
3162            },
3163            _ => Err(anyhow!("version not found on saved context")),
3164        }
3165    }
3166
3167    fn into_ops(
3168        self,
3169        buffer: &Entity<Buffer>,
3170        cx: &mut Context<AssistantContext>,
3171    ) -> Vec<ContextOperation> {
3172        let mut operations = Vec::new();
3173        let mut version = clock::Global::new();
3174        let mut next_timestamp = clock::Lamport::new(ReplicaId::default());
3175
3176        let mut first_message_metadata = None;
3177        for message in self.messages {
3178            if message.id == MessageId(clock::Lamport::default()) {
3179                first_message_metadata = Some(message.metadata);
3180            } else {
3181                operations.push(ContextOperation::InsertMessage {
3182                    anchor: MessageAnchor {
3183                        id: message.id,
3184                        start: buffer.read(cx).anchor_before(message.start),
3185                    },
3186                    metadata: MessageMetadata {
3187                        role: message.metadata.role,
3188                        status: message.metadata.status,
3189                        timestamp: message.metadata.timestamp,
3190                        cache: None,
3191                    },
3192                    version: version.clone(),
3193                });
3194                version.observe(message.id.0);
3195                next_timestamp.observe(message.id.0);
3196            }
3197        }
3198
3199        if let Some(metadata) = first_message_metadata {
3200            let timestamp = next_timestamp.tick();
3201            operations.push(ContextOperation::UpdateMessage {
3202                message_id: MessageId(clock::Lamport::default()),
3203                metadata: MessageMetadata {
3204                    role: metadata.role,
3205                    status: metadata.status,
3206                    timestamp,
3207                    cache: None,
3208                },
3209                version: version.clone(),
3210            });
3211            version.observe(timestamp);
3212        }
3213
3214        let buffer = buffer.read(cx);
3215        for section in self.slash_command_output_sections {
3216            let timestamp = next_timestamp.tick();
3217            operations.push(ContextOperation::SlashCommandOutputSectionAdded {
3218                timestamp,
3219                section: SlashCommandOutputSection {
3220                    range: buffer.anchor_after(section.range.start)
3221                        ..buffer.anchor_before(section.range.end),
3222                    icon: section.icon,
3223                    label: section.label,
3224                    metadata: section.metadata,
3225                },
3226                version: version.clone(),
3227            });
3228
3229            version.observe(timestamp);
3230        }
3231
3232        let timestamp = next_timestamp.tick();
3233        operations.push(ContextOperation::UpdateSummary {
3234            summary: ContextSummary {
3235                text: self.summary,
3236                done: true,
3237                timestamp,
3238            },
3239            version: version.clone(),
3240        });
3241        version.observe(timestamp);
3242
3243        operations
3244    }
3245}
3246
3247#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
3248struct SavedMessageIdPreV0_4_0(usize);
3249
3250#[derive(Serialize, Deserialize)]
3251struct SavedMessagePreV0_4_0 {
3252    id: SavedMessageIdPreV0_4_0,
3253    start: usize,
3254}
3255
3256#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
3257struct SavedMessageMetadataPreV0_4_0 {
3258    role: Role,
3259    status: MessageStatus,
3260}
3261
3262#[derive(Serialize, Deserialize)]
3263struct SavedContextV0_3_0 {
3264    id: Option<ContextId>,
3265    zed: String,
3266    version: String,
3267    text: String,
3268    messages: Vec<SavedMessagePreV0_4_0>,
3269    message_metadata: HashMap<SavedMessageIdPreV0_4_0, SavedMessageMetadataPreV0_4_0>,
3270    summary: String,
3271    slash_command_output_sections: Vec<assistant_slash_command::SlashCommandOutputSection<usize>>,
3272}
3273
3274impl SavedContextV0_3_0 {
3275    const VERSION: &'static str = "0.3.0";
3276
3277    fn upgrade(self) -> SavedContext {
3278        SavedContext {
3279            id: self.id,
3280            zed: self.zed,
3281            version: SavedContext::VERSION.into(),
3282            text: self.text,
3283            messages: self
3284                .messages
3285                .into_iter()
3286                .filter_map(|message| {
3287                    let metadata = self.message_metadata.get(&message.id)?;
3288                    let timestamp = clock::Lamport {
3289                        replica_id: ReplicaId::default(),
3290                        value: message.id.0 as u32,
3291                    };
3292                    Some(SavedMessage {
3293                        id: MessageId(timestamp),
3294                        start: message.start,
3295                        metadata: MessageMetadata {
3296                            role: metadata.role,
3297                            status: metadata.status.clone(),
3298                            timestamp,
3299                            cache: None,
3300                        },
3301                    })
3302                })
3303                .collect(),
3304            summary: self.summary,
3305            slash_command_output_sections: self.slash_command_output_sections,
3306        }
3307    }
3308}
3309
3310#[derive(Serialize, Deserialize)]
3311struct SavedContextV0_2_0 {
3312    id: Option<ContextId>,
3313    zed: String,
3314    version: String,
3315    text: String,
3316    messages: Vec<SavedMessagePreV0_4_0>,
3317    message_metadata: HashMap<SavedMessageIdPreV0_4_0, SavedMessageMetadataPreV0_4_0>,
3318    summary: String,
3319}
3320
3321impl SavedContextV0_2_0 {
3322    const VERSION: &'static str = "0.2.0";
3323
3324    fn upgrade(self) -> SavedContext {
3325        SavedContextV0_3_0 {
3326            id: self.id,
3327            zed: self.zed,
3328            version: SavedContextV0_3_0::VERSION.to_string(),
3329            text: self.text,
3330            messages: self.messages,
3331            message_metadata: self.message_metadata,
3332            summary: self.summary,
3333            slash_command_output_sections: Vec::new(),
3334        }
3335        .upgrade()
3336    }
3337}
3338
3339#[derive(Serialize, Deserialize)]
3340struct SavedContextV0_1_0 {
3341    id: Option<ContextId>,
3342    zed: String,
3343    version: String,
3344    text: String,
3345    messages: Vec<SavedMessagePreV0_4_0>,
3346    message_metadata: HashMap<SavedMessageIdPreV0_4_0, SavedMessageMetadataPreV0_4_0>,
3347    summary: String,
3348    api_url: Option<String>,
3349    model: OpenAiModel,
3350}
3351
3352impl SavedContextV0_1_0 {
3353    const VERSION: &'static str = "0.1.0";
3354
3355    fn upgrade(self) -> SavedContext {
3356        SavedContextV0_2_0 {
3357            id: self.id,
3358            zed: self.zed,
3359            version: SavedContextV0_2_0::VERSION.to_string(),
3360            text: self.text,
3361            messages: self.messages,
3362            message_metadata: self.message_metadata,
3363            summary: self.summary,
3364        }
3365        .upgrade()
3366    }
3367}
3368
3369#[derive(Debug, Clone)]
3370pub struct SavedContextMetadata {
3371    pub title: String,
3372    pub path: PathBuf,
3373    pub mtime: chrono::DateTime<chrono::Local>,
3374}