wit.rs

   1mod since_v0_0_1;
   2mod since_v0_0_4;
   3mod since_v0_0_6;
   4mod since_v0_1_0;
   5mod since_v0_2_0;
   6mod since_v0_3_0;
   7mod since_v0_4_0;
   8mod since_v0_5_0;
   9mod since_v0_6_0;
  10mod since_v0_7_0;
  11use dap::DebugRequest;
  12use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
  13use gpui::BackgroundExecutor;
  14use language::LanguageName;
  15use lsp::LanguageServerName;
  16use release_channel::ReleaseChannel;
  17use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
  18
  19use crate::wasm_host::wit::since_v0_7_0::dap::StartDebuggingRequestArgumentsRequest;
  20
  21use super::{WasmState, wasm_engine};
  22use anyhow::{Context as _, Result, anyhow};
  23use semver::Version;
  24use since_v0_7_0 as latest;
  25use std::{ops::RangeInclusive, path::PathBuf, sync::Arc};
  26use wasmtime::{
  27    Store,
  28    component::{Component, Linker, Resource},
  29};
  30
  31#[cfg(test)]
  32pub use latest::CodeLabelSpanLiteral;
  33pub use latest::{
  34    CodeLabel, CodeLabelSpan, Command, DebugAdapterBinary, ExtensionProject, Range, SlashCommand,
  35    zed::extension::context_server::ContextServerConfiguration,
  36    zed::extension::llm_provider::{
  37        CacheConfiguration as LlmCacheConfiguration, CompletionEvent as LlmCompletionEvent,
  38        CompletionRequest as LlmCompletionRequest, CredentialType as LlmCredentialType,
  39        ImageData as LlmImageData, MessageContent as LlmMessageContent,
  40        MessageRole as LlmMessageRole, ModelCapabilities as LlmModelCapabilities,
  41        ModelInfo as LlmModelInfo, ProviderInfo as LlmProviderInfo,
  42        RequestMessage as LlmRequestMessage, StopReason as LlmStopReason,
  43        ThinkingContent as LlmThinkingContent, TokenUsage as LlmTokenUsage,
  44        ToolChoice as LlmToolChoice, ToolDefinition as LlmToolDefinition,
  45        ToolInputFormat as LlmToolInputFormat, ToolResult as LlmToolResult,
  46        ToolResultContent as LlmToolResultContent, ToolUse as LlmToolUse,
  47        ToolUseJsonParseError as LlmToolUseJsonParseError,
  48    },
  49    zed::extension::lsp::{
  50        Completion, CompletionKind, CompletionLabelDetails, InsertTextFormat, Symbol, SymbolKind,
  51    },
  52    zed::extension::slash_command::{SlashCommandArgumentCompletion, SlashCommandOutput},
  53};
  54pub use since_v0_0_4::LanguageServerConfig;
  55
  56pub fn new_linker(
  57    executor: &BackgroundExecutor,
  58    f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
  59) -> Linker<WasmState> {
  60    let mut linker = Linker::new(&wasm_engine(executor));
  61    wasmtime_wasi::add_to_linker_async(&mut linker).unwrap();
  62    f(&mut linker, wasi_view).unwrap();
  63    linker
  64}
  65
  66fn wasi_view(state: &mut WasmState) -> &mut WasmState {
  67    state
  68}
  69
  70/// Returns whether the given Wasm API version is supported by the Wasm host.
  71pub fn is_supported_wasm_api_version(release_channel: ReleaseChannel, version: Version) -> bool {
  72    wasm_api_version_range(release_channel).contains(&version)
  73}
  74
  75/// Returns the Wasm API version range that is supported by the Wasm host.
  76#[inline(always)]
  77pub fn wasm_api_version_range(release_channel: ReleaseChannel) -> RangeInclusive<Version> {
  78    // Note: The release channel can be used to stage a new version of the extension API.
  79    let _ = release_channel;
  80
  81    let max_version = match release_channel {
  82        ReleaseChannel::Dev | ReleaseChannel::Nightly => latest::MAX_VERSION,
  83        ReleaseChannel::Stable | ReleaseChannel::Preview => latest::MAX_VERSION,
  84    };
  85
  86    since_v0_0_1::MIN_VERSION..=max_version
  87}
  88
  89/// Authorizes access to use unreleased versions of the Wasm API, based on the provided [`ReleaseChannel`].
  90///
  91/// Note: If there isn't currently an unreleased Wasm API version this function may be unused. Don't delete it!
  92pub fn authorize_access_to_unreleased_wasm_api_version(
  93    release_channel: ReleaseChannel,
  94) -> Result<()> {
  95    let allow_unreleased_version = match release_channel {
  96        ReleaseChannel::Dev | ReleaseChannel::Nightly => true,
  97        ReleaseChannel::Stable | ReleaseChannel::Preview => {
  98            // We always allow the latest in tests so that the extension tests pass on release branches.
  99            cfg!(any(test, feature = "test-support"))
 100        }
 101    };
 102
 103    anyhow::ensure!(
 104        allow_unreleased_version,
 105        "unreleased versions of the extension API can only be used on development builds of Zed"
 106    );
 107
 108    Ok(())
 109}
 110
 111pub enum Extension {
 112    V0_7_0(since_v0_7_0::Extension),
 113    V0_6_0(since_v0_6_0::Extension),
 114    V0_5_0(since_v0_5_0::Extension),
 115    V0_4_0(since_v0_4_0::Extension),
 116    V0_3_0(since_v0_3_0::Extension),
 117    V0_2_0(since_v0_2_0::Extension),
 118    V0_1_0(since_v0_1_0::Extension),
 119    V0_0_6(since_v0_0_6::Extension),
 120    V0_0_4(since_v0_0_4::Extension),
 121    V0_0_1(since_v0_0_1::Extension),
 122}
 123
 124impl Extension {
 125    pub async fn instantiate_async(
 126        executor: &BackgroundExecutor,
 127        store: &mut Store<WasmState>,
 128        release_channel: ReleaseChannel,
 129        version: Version,
 130        component: &Component,
 131    ) -> Result<Self> {
 132        // Note: The release channel can be used to stage a new version of the extension API.
 133        let _ = release_channel;
 134
 135        if version >= latest::MIN_VERSION {
 136            let extension =
 137                latest::Extension::instantiate_async(store, component, latest::linker(executor))
 138                    .await
 139                    .context("failed to instantiate wasm extension")?;
 140            Ok(Self::V0_7_0(extension))
 141        } else if version >= since_v0_6_0::MIN_VERSION {
 142            let extension = since_v0_6_0::Extension::instantiate_async(
 143                store,
 144                component,
 145                since_v0_6_0::linker(executor),
 146            )
 147            .await
 148            .context("failed to instantiate wasm extension")?;
 149            Ok(Self::V0_6_0(extension))
 150        } else if version >= since_v0_5_0::MIN_VERSION {
 151            let extension = since_v0_5_0::Extension::instantiate_async(
 152                store,
 153                component,
 154                since_v0_5_0::linker(executor),
 155            )
 156            .await
 157            .context("failed to instantiate wasm extension")?;
 158            Ok(Self::V0_5_0(extension))
 159        } else if version >= since_v0_4_0::MIN_VERSION {
 160            let extension = since_v0_4_0::Extension::instantiate_async(
 161                store,
 162                component,
 163                since_v0_4_0::linker(executor),
 164            )
 165            .await
 166            .context("failed to instantiate wasm extension")?;
 167            Ok(Self::V0_4_0(extension))
 168        } else if version >= since_v0_3_0::MIN_VERSION {
 169            let extension = since_v0_3_0::Extension::instantiate_async(
 170                store,
 171                component,
 172                since_v0_3_0::linker(executor),
 173            )
 174            .await
 175            .context("failed to instantiate wasm extension")?;
 176            Ok(Self::V0_3_0(extension))
 177        } else if version >= since_v0_2_0::MIN_VERSION {
 178            let extension = since_v0_2_0::Extension::instantiate_async(
 179                store,
 180                component,
 181                since_v0_2_0::linker(executor),
 182            )
 183            .await
 184            .context("failed to instantiate wasm extension")?;
 185            Ok(Self::V0_2_0(extension))
 186        } else if version >= since_v0_1_0::MIN_VERSION {
 187            let extension = since_v0_1_0::Extension::instantiate_async(
 188                store,
 189                component,
 190                since_v0_1_0::linker(executor),
 191            )
 192            .await
 193            .context("failed to instantiate wasm extension")?;
 194            Ok(Self::V0_1_0(extension))
 195        } else if version >= since_v0_0_6::MIN_VERSION {
 196            let extension = since_v0_0_6::Extension::instantiate_async(
 197                store,
 198                component,
 199                since_v0_0_6::linker(executor),
 200            )
 201            .await
 202            .context("failed to instantiate wasm extension")?;
 203            Ok(Self::V0_0_6(extension))
 204        } else if version >= since_v0_0_4::MIN_VERSION {
 205            let extension = since_v0_0_4::Extension::instantiate_async(
 206                store,
 207                component,
 208                since_v0_0_4::linker(executor),
 209            )
 210            .await
 211            .context("failed to instantiate wasm extension")?;
 212            Ok(Self::V0_0_4(extension))
 213        } else {
 214            let extension = since_v0_0_1::Extension::instantiate_async(
 215                store,
 216                component,
 217                since_v0_0_1::linker(executor),
 218            )
 219            .await
 220            .context("failed to instantiate wasm extension")?;
 221            Ok(Self::V0_0_1(extension))
 222        }
 223    }
 224
 225    pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
 226        match self {
 227            Extension::V0_7_0(ext) => ext.call_init_extension(store).await,
 228            Extension::V0_6_0(ext) => ext.call_init_extension(store).await,
 229            Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
 230            Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
 231            Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
 232            Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
 233            Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
 234            Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
 235            Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
 236            Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
 237        }
 238    }
 239
 240    pub async fn call_language_server_command(
 241        &self,
 242        store: &mut Store<WasmState>,
 243        language_server_id: &LanguageServerName,
 244        language_name: &LanguageName,
 245        resource: Resource<Arc<dyn WorktreeDelegate>>,
 246    ) -> Result<Result<Command, String>> {
 247        match self {
 248            Extension::V0_7_0(ext) => {
 249                ext.call_language_server_command(store, &language_server_id.0, resource)
 250                    .await
 251            }
 252            Extension::V0_6_0(ext) => {
 253                ext.call_language_server_command(store, &language_server_id.0, resource)
 254                    .await
 255            }
 256            Extension::V0_5_0(ext) => {
 257                ext.call_language_server_command(store, &language_server_id.0, resource)
 258                    .await
 259            }
 260            Extension::V0_4_0(ext) => {
 261                ext.call_language_server_command(store, &language_server_id.0, resource)
 262                    .await
 263            }
 264            Extension::V0_3_0(ext) => {
 265                ext.call_language_server_command(store, &language_server_id.0, resource)
 266                    .await
 267            }
 268            Extension::V0_2_0(ext) => Ok(ext
 269                .call_language_server_command(store, &language_server_id.0, resource)
 270                .await?
 271                .map(|command| command.into())),
 272            Extension::V0_1_0(ext) => Ok(ext
 273                .call_language_server_command(store, &language_server_id.0, resource)
 274                .await?
 275                .map(|command| command.into())),
 276            Extension::V0_0_6(ext) => Ok(ext
 277                .call_language_server_command(store, &language_server_id.0, resource)
 278                .await?
 279                .map(|command| command.into())),
 280            Extension::V0_0_4(ext) => Ok(ext
 281                .call_language_server_command(
 282                    store,
 283                    &LanguageServerConfig {
 284                        name: language_server_id.0.to_string(),
 285                        language_name: language_name.to_string(),
 286                    },
 287                    resource,
 288                )
 289                .await?
 290                .map(|command| command.into())),
 291            Extension::V0_0_1(ext) => Ok(ext
 292                .call_language_server_command(
 293                    store,
 294                    &LanguageServerConfig {
 295                        name: language_server_id.0.to_string(),
 296                        language_name: language_name.to_string(),
 297                    }
 298                    .into(),
 299                    resource,
 300                )
 301                .await?
 302                .map(|command| command.into())),
 303        }
 304    }
 305
 306    pub async fn call_language_server_initialization_options(
 307        &self,
 308        store: &mut Store<WasmState>,
 309        language_server_id: &LanguageServerName,
 310        language_name: &LanguageName,
 311        resource: Resource<Arc<dyn WorktreeDelegate>>,
 312    ) -> Result<Result<Option<String>, String>> {
 313        match self {
 314            Extension::V0_7_0(ext) => {
 315                ext.call_language_server_initialization_options(
 316                    store,
 317                    &language_server_id.0,
 318                    resource,
 319                )
 320                .await
 321            }
 322            Extension::V0_6_0(ext) => {
 323                ext.call_language_server_initialization_options(
 324                    store,
 325                    &language_server_id.0,
 326                    resource,
 327                )
 328                .await
 329            }
 330            Extension::V0_5_0(ext) => {
 331                ext.call_language_server_initialization_options(
 332                    store,
 333                    &language_server_id.0,
 334                    resource,
 335                )
 336                .await
 337            }
 338            Extension::V0_4_0(ext) => {
 339                ext.call_language_server_initialization_options(
 340                    store,
 341                    &language_server_id.0,
 342                    resource,
 343                )
 344                .await
 345            }
 346            Extension::V0_3_0(ext) => {
 347                ext.call_language_server_initialization_options(
 348                    store,
 349                    &language_server_id.0,
 350                    resource,
 351                )
 352                .await
 353            }
 354            Extension::V0_2_0(ext) => {
 355                ext.call_language_server_initialization_options(
 356                    store,
 357                    &language_server_id.0,
 358                    resource,
 359                )
 360                .await
 361            }
 362            Extension::V0_1_0(ext) => {
 363                ext.call_language_server_initialization_options(
 364                    store,
 365                    &language_server_id.0,
 366                    resource,
 367                )
 368                .await
 369            }
 370            Extension::V0_0_6(ext) => {
 371                ext.call_language_server_initialization_options(
 372                    store,
 373                    &language_server_id.0,
 374                    resource,
 375                )
 376                .await
 377            }
 378            Extension::V0_0_4(ext) => {
 379                ext.call_language_server_initialization_options(
 380                    store,
 381                    &LanguageServerConfig {
 382                        name: language_server_id.0.to_string(),
 383                        language_name: language_name.to_string(),
 384                    },
 385                    resource,
 386                )
 387                .await
 388            }
 389            Extension::V0_0_1(ext) => {
 390                ext.call_language_server_initialization_options(
 391                    store,
 392                    &LanguageServerConfig {
 393                        name: language_server_id.0.to_string(),
 394                        language_name: language_name.to_string(),
 395                    }
 396                    .into(),
 397                    resource,
 398                )
 399                .await
 400            }
 401        }
 402    }
 403
 404    pub async fn call_language_server_workspace_configuration(
 405        &self,
 406        store: &mut Store<WasmState>,
 407        language_server_id: &LanguageServerName,
 408        resource: Resource<Arc<dyn WorktreeDelegate>>,
 409    ) -> Result<Result<Option<String>, String>> {
 410        match self {
 411            Extension::V0_7_0(ext) => {
 412                ext.call_language_server_workspace_configuration(
 413                    store,
 414                    &language_server_id.0,
 415                    resource,
 416                )
 417                .await
 418            }
 419            Extension::V0_6_0(ext) => {
 420                ext.call_language_server_workspace_configuration(
 421                    store,
 422                    &language_server_id.0,
 423                    resource,
 424                )
 425                .await
 426            }
 427            Extension::V0_5_0(ext) => {
 428                ext.call_language_server_workspace_configuration(
 429                    store,
 430                    &language_server_id.0,
 431                    resource,
 432                )
 433                .await
 434            }
 435            Extension::V0_4_0(ext) => {
 436                ext.call_language_server_workspace_configuration(
 437                    store,
 438                    &language_server_id.0,
 439                    resource,
 440                )
 441                .await
 442            }
 443            Extension::V0_3_0(ext) => {
 444                ext.call_language_server_workspace_configuration(
 445                    store,
 446                    &language_server_id.0,
 447                    resource,
 448                )
 449                .await
 450            }
 451            Extension::V0_2_0(ext) => {
 452                ext.call_language_server_workspace_configuration(
 453                    store,
 454                    &language_server_id.0,
 455                    resource,
 456                )
 457                .await
 458            }
 459            Extension::V0_1_0(ext) => {
 460                ext.call_language_server_workspace_configuration(
 461                    store,
 462                    &language_server_id.0,
 463                    resource,
 464                )
 465                .await
 466            }
 467            Extension::V0_0_6(ext) => {
 468                ext.call_language_server_workspace_configuration(
 469                    store,
 470                    &language_server_id.0,
 471                    resource,
 472                )
 473                .await
 474            }
 475            Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
 476        }
 477    }
 478
 479    pub async fn call_language_server_additional_initialization_options(
 480        &self,
 481        store: &mut Store<WasmState>,
 482        language_server_id: &LanguageServerName,
 483        target_language_server_id: &LanguageServerName,
 484        resource: Resource<Arc<dyn WorktreeDelegate>>,
 485    ) -> Result<Result<Option<String>, String>> {
 486        match self {
 487            Extension::V0_7_0(ext) => {
 488                ext.call_language_server_additional_initialization_options(
 489                    store,
 490                    &language_server_id.0,
 491                    &target_language_server_id.0,
 492                    resource,
 493                )
 494                .await
 495            }
 496            Extension::V0_6_0(ext) => {
 497                ext.call_language_server_additional_initialization_options(
 498                    store,
 499                    &language_server_id.0,
 500                    &target_language_server_id.0,
 501                    resource,
 502                )
 503                .await
 504            }
 505            Extension::V0_5_0(ext) => {
 506                ext.call_language_server_additional_initialization_options(
 507                    store,
 508                    &language_server_id.0,
 509                    &target_language_server_id.0,
 510                    resource,
 511                )
 512                .await
 513            }
 514            Extension::V0_4_0(ext) => {
 515                ext.call_language_server_additional_initialization_options(
 516                    store,
 517                    &language_server_id.0,
 518                    &target_language_server_id.0,
 519                    resource,
 520                )
 521                .await
 522            }
 523            Extension::V0_3_0(_)
 524            | Extension::V0_2_0(_)
 525            | Extension::V0_1_0(_)
 526            | Extension::V0_0_6(_)
 527            | Extension::V0_0_4(_)
 528            | Extension::V0_0_1(_) => Ok(Ok(None)),
 529        }
 530    }
 531
 532    pub async fn call_language_server_additional_workspace_configuration(
 533        &self,
 534        store: &mut Store<WasmState>,
 535        language_server_id: &LanguageServerName,
 536        target_language_server_id: &LanguageServerName,
 537        resource: Resource<Arc<dyn WorktreeDelegate>>,
 538    ) -> Result<Result<Option<String>, String>> {
 539        match self {
 540            Extension::V0_7_0(ext) => {
 541                ext.call_language_server_additional_workspace_configuration(
 542                    store,
 543                    &language_server_id.0,
 544                    &target_language_server_id.0,
 545                    resource,
 546                )
 547                .await
 548            }
 549            Extension::V0_6_0(ext) => {
 550                ext.call_language_server_additional_workspace_configuration(
 551                    store,
 552                    &language_server_id.0,
 553                    &target_language_server_id.0,
 554                    resource,
 555                )
 556                .await
 557            }
 558            Extension::V0_5_0(ext) => {
 559                ext.call_language_server_additional_workspace_configuration(
 560                    store,
 561                    &language_server_id.0,
 562                    &target_language_server_id.0,
 563                    resource,
 564                )
 565                .await
 566            }
 567            Extension::V0_4_0(ext) => {
 568                ext.call_language_server_additional_workspace_configuration(
 569                    store,
 570                    &language_server_id.0,
 571                    &target_language_server_id.0,
 572                    resource,
 573                )
 574                .await
 575            }
 576            Extension::V0_3_0(_)
 577            | Extension::V0_2_0(_)
 578            | Extension::V0_1_0(_)
 579            | Extension::V0_0_6(_)
 580            | Extension::V0_0_4(_)
 581            | Extension::V0_0_1(_) => Ok(Ok(None)),
 582        }
 583    }
 584
 585    pub async fn call_labels_for_completions(
 586        &self,
 587        store: &mut Store<WasmState>,
 588        language_server_id: &LanguageServerName,
 589        completions: Vec<latest::Completion>,
 590    ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
 591        match self {
 592            Extension::V0_7_0(ext) => {
 593                ext.call_labels_for_completions(store, &language_server_id.0, &completions)
 594                    .await
 595            }
 596            Extension::V0_6_0(ext) => Ok(ext
 597                .call_labels_for_completions(
 598                    store,
 599                    &language_server_id.0,
 600                    &completions.into_iter().collect::<Vec<_>>(),
 601                )
 602                .await?
 603                .map(|labels| {
 604                    labels
 605                        .into_iter()
 606                        .map(|label| label.map(Into::into))
 607                        .collect()
 608                })),
 609            Extension::V0_5_0(ext) => Ok(ext
 610                .call_labels_for_completions(
 611                    store,
 612                    &language_server_id.0,
 613                    &completions.into_iter().collect::<Vec<_>>(),
 614                )
 615                .await?
 616                .map(|labels| {
 617                    labels
 618                        .into_iter()
 619                        .map(|label| label.map(Into::into))
 620                        .collect()
 621                })),
 622            Extension::V0_4_0(ext) => Ok(ext
 623                .call_labels_for_completions(
 624                    store,
 625                    &language_server_id.0,
 626                    &completions.into_iter().collect::<Vec<_>>(),
 627                )
 628                .await?
 629                .map(|labels| {
 630                    labels
 631                        .into_iter()
 632                        .map(|label| label.map(Into::into))
 633                        .collect()
 634                })),
 635            Extension::V0_3_0(ext) => Ok(ext
 636                .call_labels_for_completions(
 637                    store,
 638                    &language_server_id.0,
 639                    &completions.into_iter().collect::<Vec<_>>(),
 640                )
 641                .await?
 642                .map(|labels| {
 643                    labels
 644                        .into_iter()
 645                        .map(|label| label.map(Into::into))
 646                        .collect()
 647                })),
 648            Extension::V0_2_0(ext) => Ok(ext
 649                .call_labels_for_completions(
 650                    store,
 651                    &language_server_id.0,
 652                    &completions.into_iter().collect::<Vec<_>>(),
 653                )
 654                .await?
 655                .map(|labels| {
 656                    labels
 657                        .into_iter()
 658                        .map(|label| label.map(Into::into))
 659                        .collect()
 660                })),
 661            Extension::V0_1_0(ext) => Ok(ext
 662                .call_labels_for_completions(
 663                    store,
 664                    &language_server_id.0,
 665                    &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
 666                )
 667                .await?
 668                .map(|labels| {
 669                    labels
 670                        .into_iter()
 671                        .map(|label| label.map(Into::into))
 672                        .collect()
 673                })),
 674            Extension::V0_0_6(ext) => Ok(ext
 675                .call_labels_for_completions(
 676                    store,
 677                    &language_server_id.0,
 678                    &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
 679                )
 680                .await?
 681                .map(|labels| {
 682                    labels
 683                        .into_iter()
 684                        .map(|label| label.map(Into::into))
 685                        .collect()
 686                })),
 687            Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
 688        }
 689    }
 690
 691    pub async fn call_labels_for_symbols(
 692        &self,
 693        store: &mut Store<WasmState>,
 694        language_server_id: &LanguageServerName,
 695        symbols: Vec<latest::Symbol>,
 696    ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
 697        match self {
 698            Extension::V0_7_0(ext) => {
 699                ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
 700                    .await
 701            }
 702            Extension::V0_6_0(ext) => Ok(ext
 703                .call_labels_for_symbols(
 704                    store,
 705                    &language_server_id.0,
 706                    &symbols.into_iter().collect::<Vec<_>>(),
 707                )
 708                .await?
 709                .map(|labels| {
 710                    labels
 711                        .into_iter()
 712                        .map(|label| label.map(Into::into))
 713                        .collect()
 714                })),
 715            Extension::V0_5_0(ext) => Ok(ext
 716                .call_labels_for_symbols(
 717                    store,
 718                    &language_server_id.0,
 719                    &symbols.into_iter().collect::<Vec<_>>(),
 720                )
 721                .await?
 722                .map(|labels| {
 723                    labels
 724                        .into_iter()
 725                        .map(|label| label.map(Into::into))
 726                        .collect()
 727                })),
 728            Extension::V0_4_0(ext) => Ok(ext
 729                .call_labels_for_symbols(
 730                    store,
 731                    &language_server_id.0,
 732                    &symbols.into_iter().collect::<Vec<_>>(),
 733                )
 734                .await?
 735                .map(|labels| {
 736                    labels
 737                        .into_iter()
 738                        .map(|label| label.map(Into::into))
 739                        .collect()
 740                })),
 741            Extension::V0_3_0(ext) => Ok(ext
 742                .call_labels_for_symbols(
 743                    store,
 744                    &language_server_id.0,
 745                    &symbols.into_iter().collect::<Vec<_>>(),
 746                )
 747                .await?
 748                .map(|labels| {
 749                    labels
 750                        .into_iter()
 751                        .map(|label| label.map(Into::into))
 752                        .collect()
 753                })),
 754            Extension::V0_2_0(ext) => Ok(ext
 755                .call_labels_for_symbols(
 756                    store,
 757                    &language_server_id.0,
 758                    &symbols.into_iter().collect::<Vec<_>>(),
 759                )
 760                .await?
 761                .map(|labels| {
 762                    labels
 763                        .into_iter()
 764                        .map(|label| label.map(Into::into))
 765                        .collect()
 766                })),
 767            Extension::V0_1_0(ext) => Ok(ext
 768                .call_labels_for_symbols(
 769                    store,
 770                    &language_server_id.0,
 771                    &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
 772                )
 773                .await?
 774                .map(|labels| {
 775                    labels
 776                        .into_iter()
 777                        .map(|label| label.map(Into::into))
 778                        .collect()
 779                })),
 780            Extension::V0_0_6(ext) => Ok(ext
 781                .call_labels_for_symbols(
 782                    store,
 783                    &language_server_id.0,
 784                    &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
 785                )
 786                .await?
 787                .map(|labels| {
 788                    labels
 789                        .into_iter()
 790                        .map(|label| label.map(Into::into))
 791                        .collect()
 792                })),
 793            Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
 794        }
 795    }
 796
 797    pub async fn call_complete_slash_command_argument(
 798        &self,
 799        store: &mut Store<WasmState>,
 800        command: &SlashCommand,
 801        arguments: &[String],
 802    ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
 803        match self {
 804            Extension::V0_7_0(ext) => {
 805                ext.call_complete_slash_command_argument(store, command, arguments)
 806                    .await
 807            }
 808            Extension::V0_6_0(ext) => {
 809                ext.call_complete_slash_command_argument(store, command, arguments)
 810                    .await
 811            }
 812            Extension::V0_5_0(ext) => {
 813                ext.call_complete_slash_command_argument(store, command, arguments)
 814                    .await
 815            }
 816            Extension::V0_4_0(ext) => {
 817                ext.call_complete_slash_command_argument(store, command, arguments)
 818                    .await
 819            }
 820            Extension::V0_3_0(ext) => {
 821                ext.call_complete_slash_command_argument(store, command, arguments)
 822                    .await
 823            }
 824            Extension::V0_2_0(ext) => {
 825                ext.call_complete_slash_command_argument(store, command, arguments)
 826                    .await
 827            }
 828            Extension::V0_1_0(ext) => {
 829                ext.call_complete_slash_command_argument(store, command, arguments)
 830                    .await
 831            }
 832            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 833                Ok(Ok(Vec::new()))
 834            }
 835        }
 836    }
 837
 838    pub async fn call_run_slash_command(
 839        &self,
 840        store: &mut Store<WasmState>,
 841        command: &SlashCommand,
 842        arguments: &[String],
 843        resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
 844    ) -> Result<Result<SlashCommandOutput, String>> {
 845        match self {
 846            Extension::V0_7_0(ext) => {
 847                ext.call_run_slash_command(store, command, arguments, resource)
 848                    .await
 849            }
 850            Extension::V0_6_0(ext) => {
 851                ext.call_run_slash_command(store, command, arguments, resource)
 852                    .await
 853            }
 854            Extension::V0_5_0(ext) => {
 855                ext.call_run_slash_command(store, command, arguments, resource)
 856                    .await
 857            }
 858            Extension::V0_4_0(ext) => {
 859                ext.call_run_slash_command(store, command, arguments, resource)
 860                    .await
 861            }
 862            Extension::V0_3_0(ext) => {
 863                ext.call_run_slash_command(store, command, arguments, resource)
 864                    .await
 865            }
 866            Extension::V0_2_0(ext) => {
 867                ext.call_run_slash_command(store, command, arguments, resource)
 868                    .await
 869            }
 870            Extension::V0_1_0(ext) => {
 871                ext.call_run_slash_command(store, command, arguments, resource)
 872                    .await
 873            }
 874            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 875                anyhow::bail!("`run_slash_command` not available prior to v0.1.0");
 876            }
 877        }
 878    }
 879
 880    pub async fn call_context_server_command(
 881        &self,
 882        store: &mut Store<WasmState>,
 883        context_server_id: Arc<str>,
 884        project: Resource<ExtensionProject>,
 885    ) -> Result<Result<Command, String>> {
 886        match self {
 887            Extension::V0_7_0(ext) => {
 888                ext.call_context_server_command(store, &context_server_id, project)
 889                    .await
 890            }
 891            Extension::V0_6_0(ext) => {
 892                ext.call_context_server_command(store, &context_server_id, project)
 893                    .await
 894            }
 895            Extension::V0_5_0(ext) => {
 896                ext.call_context_server_command(store, &context_server_id, project)
 897                    .await
 898            }
 899            Extension::V0_4_0(ext) => {
 900                ext.call_context_server_command(store, &context_server_id, project)
 901                    .await
 902            }
 903            Extension::V0_3_0(ext) => {
 904                ext.call_context_server_command(store, &context_server_id, project)
 905                    .await
 906            }
 907            Extension::V0_2_0(ext) => Ok(ext
 908                .call_context_server_command(store, &context_server_id, project)
 909                .await?
 910                .map(Into::into)),
 911            Extension::V0_0_1(_)
 912            | Extension::V0_0_4(_)
 913            | Extension::V0_0_6(_)
 914            | Extension::V0_1_0(_) => {
 915                anyhow::bail!("`context_server_command` not available prior to v0.2.0");
 916            }
 917        }
 918    }
 919
 920    pub async fn call_context_server_configuration(
 921        &self,
 922        store: &mut Store<WasmState>,
 923        context_server_id: Arc<str>,
 924        project: Resource<ExtensionProject>,
 925    ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
 926        match self {
 927            Extension::V0_7_0(ext) => {
 928                ext.call_context_server_configuration(store, &context_server_id, project)
 929                    .await
 930            }
 931            Extension::V0_6_0(ext) => {
 932                ext.call_context_server_configuration(store, &context_server_id, project)
 933                    .await
 934            }
 935            Extension::V0_5_0(ext) => {
 936                ext.call_context_server_configuration(store, &context_server_id, project)
 937                    .await
 938            }
 939            Extension::V0_0_1(_)
 940            | Extension::V0_0_4(_)
 941            | Extension::V0_0_6(_)
 942            | Extension::V0_1_0(_)
 943            | Extension::V0_2_0(_)
 944            | Extension::V0_3_0(_)
 945            | Extension::V0_4_0(_) => {
 946                anyhow::bail!("`context_server_configuration` not available prior to v0.5.0");
 947            }
 948        }
 949    }
 950
 951    pub async fn call_suggest_docs_packages(
 952        &self,
 953        store: &mut Store<WasmState>,
 954        provider: &str,
 955    ) -> Result<Result<Vec<String>, String>> {
 956        match self {
 957            Extension::V0_7_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 958            Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 959            Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 960            Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 961            Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 962            Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 963            Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
 964            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
 965                anyhow::bail!("`suggest_docs_packages` not available prior to v0.1.0");
 966            }
 967        }
 968    }
 969
 970    pub async fn call_index_docs(
 971        &self,
 972        store: &mut Store<WasmState>,
 973        provider: &str,
 974        package_name: &str,
 975        kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
 976    ) -> Result<Result<(), String>> {
 977        match self {
 978            Extension::V0_7_0(ext) => {
 979                ext.call_index_docs(store, provider, package_name, kv_store)
 980                    .await
 981            }
 982            Extension::V0_6_0(ext) => {
 983                ext.call_index_docs(store, provider, package_name, kv_store)
 984                    .await
 985            }
 986            Extension::V0_5_0(ext) => {
 987                ext.call_index_docs(store, provider, package_name, kv_store)
 988                    .await
 989            }
 990            Extension::V0_4_0(ext) => {
 991                ext.call_index_docs(store, provider, package_name, kv_store)
 992                    .await
 993            }
 994            Extension::V0_3_0(ext) => {
 995                ext.call_index_docs(store, provider, package_name, kv_store)
 996                    .await
 997            }
 998            Extension::V0_2_0(ext) => {
 999                ext.call_index_docs(store, provider, package_name, kv_store)
1000                    .await
1001            }
1002            Extension::V0_1_0(ext) => {
1003                ext.call_index_docs(store, provider, package_name, kv_store)
1004                    .await
1005            }
1006            Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
1007                anyhow::bail!("`index_docs` not available prior to v0.1.0");
1008            }
1009        }
1010    }
1011    pub async fn call_get_dap_binary(
1012        &self,
1013        store: &mut Store<WasmState>,
1014        adapter_name: Arc<str>,
1015        task: DebugTaskDefinition,
1016        user_installed_path: Option<PathBuf>,
1017        resource: Resource<Arc<dyn WorktreeDelegate>>,
1018    ) -> Result<Result<DebugAdapterBinary, String>> {
1019        match self {
1020            Extension::V0_7_0(ext) => {
1021                let dap_binary = ext
1022                    .call_get_dap_binary(
1023                        store,
1024                        &adapter_name,
1025                        &task.try_into()?,
1026                        user_installed_path.as_ref().and_then(|p| p.to_str()),
1027                        resource,
1028                    )
1029                    .await?
1030                    .map_err(|e| anyhow!("{e:?}"))?;
1031
1032                Ok(Ok(dap_binary))
1033            }
1034            Extension::V0_6_0(ext) => {
1035                let dap_binary = ext
1036                    .call_get_dap_binary(
1037                        store,
1038                        &adapter_name,
1039                        &task.try_into()?,
1040                        user_installed_path.as_ref().and_then(|p| p.to_str()),
1041                        resource,
1042                    )
1043                    .await?
1044                    .map_err(|e| anyhow!("{e:?}"))?;
1045
1046                Ok(Ok(dap_binary))
1047            }
1048            _ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
1049        }
1050    }
1051    pub async fn call_dap_request_kind(
1052        &self,
1053        store: &mut Store<WasmState>,
1054        adapter_name: Arc<str>,
1055        config: serde_json::Value,
1056    ) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
1057        match self {
1058            Extension::V0_7_0(ext) => {
1059                let config =
1060                    serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1061                let dap_binary = ext
1062                    .call_dap_request_kind(store, &adapter_name, &config)
1063                    .await?
1064                    .map_err(|e| anyhow!("{e:?}"))?;
1065
1066                Ok(Ok(dap_binary))
1067            }
1068            Extension::V0_6_0(ext) => {
1069                let config =
1070                    serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1071                let dap_binary = ext
1072                    .call_dap_request_kind(store, &adapter_name, &config)
1073                    .await?
1074                    .map_err(|e| anyhow!("{e:?}"))?;
1075
1076                Ok(Ok(dap_binary))
1077            }
1078            _ => anyhow::bail!("`dap_request_kind` not available prior to v0.6.0"),
1079        }
1080    }
1081    pub async fn call_dap_config_to_scenario(
1082        &self,
1083        store: &mut Store<WasmState>,
1084        config: ZedDebugConfig,
1085    ) -> Result<Result<DebugScenario, String>> {
1086        match self {
1087            Extension::V0_7_0(ext) => {
1088                let config = config.into();
1089                let dap_binary = ext
1090                    .call_dap_config_to_scenario(store, &config)
1091                    .await?
1092                    .map_err(|e| anyhow!("{e:?}"))?;
1093
1094                Ok(Ok(dap_binary.try_into()?))
1095            }
1096            Extension::V0_6_0(ext) => {
1097                let config = config.into();
1098                let dap_binary = ext
1099                    .call_dap_config_to_scenario(store, &config)
1100                    .await?
1101                    .map_err(|e| anyhow!("{e:?}"))?;
1102
1103                Ok(Ok(dap_binary.try_into()?))
1104            }
1105            _ => anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0"),
1106        }
1107    }
1108    pub async fn call_dap_locator_create_scenario(
1109        &self,
1110        store: &mut Store<WasmState>,
1111        locator_name: String,
1112        build_config_template: TaskTemplate,
1113        resolved_label: String,
1114        debug_adapter_name: String,
1115    ) -> Result<Option<DebugScenario>> {
1116        match self {
1117            Extension::V0_7_0(ext) => {
1118                let build_config_template = build_config_template.into();
1119                let dap_binary = ext
1120                    .call_dap_locator_create_scenario(
1121                        store,
1122                        &locator_name,
1123                        &build_config_template,
1124                        &resolved_label,
1125                        &debug_adapter_name,
1126                    )
1127                    .await?;
1128
1129                Ok(dap_binary.map(TryInto::try_into).transpose()?)
1130            }
1131            Extension::V0_6_0(ext) => {
1132                let build_config_template = build_config_template.into();
1133                let dap_binary = ext
1134                    .call_dap_locator_create_scenario(
1135                        store,
1136                        &locator_name,
1137                        &build_config_template,
1138                        &resolved_label,
1139                        &debug_adapter_name,
1140                    )
1141                    .await?;
1142
1143                Ok(dap_binary.map(TryInto::try_into).transpose()?)
1144            }
1145            _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1146        }
1147    }
1148    pub async fn call_run_dap_locator(
1149        &self,
1150        store: &mut Store<WasmState>,
1151        locator_name: String,
1152        resolved_build_task: SpawnInTerminal,
1153    ) -> Result<Result<DebugRequest, String>> {
1154        match self {
1155            Extension::V0_7_0(ext) => {
1156                let build_config_template = resolved_build_task.try_into()?;
1157                let dap_request = ext
1158                    .call_run_dap_locator(store, &locator_name, &build_config_template)
1159                    .await?
1160                    .map_err(|e| anyhow!("{e:?}"))?;
1161
1162                Ok(Ok(dap_request.into()))
1163            }
1164            Extension::V0_6_0(ext) => {
1165                let build_config_template = resolved_build_task.try_into()?;
1166                let dap_request = ext
1167                    .call_run_dap_locator(store, &locator_name, &build_config_template)
1168                    .await?
1169                    .map_err(|e| anyhow!("{e:?}"))?;
1170
1171                Ok(Ok(dap_request.into()))
1172            }
1173            _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1174        }
1175    }
1176
1177    // =========================================================================
1178    // LLM Provider Methods (v0.7.0+)
1179    // =========================================================================
1180
1181    pub async fn call_llm_providers(
1182        &self,
1183        store: &mut Store<WasmState>,
1184    ) -> Result<Vec<latest::llm_provider::ProviderInfo>> {
1185        match self {
1186            Extension::V0_7_0(ext) => ext.call_llm_providers(store).await,
1187            _ => Ok(Vec::new()),
1188        }
1189    }
1190
1191    pub async fn call_llm_provider_models(
1192        &self,
1193        store: &mut Store<WasmState>,
1194        provider_id: &str,
1195    ) -> Result<Result<Vec<latest::llm_provider::ModelInfo>, String>> {
1196        match self {
1197            Extension::V0_7_0(ext) => ext.call_llm_provider_models(store, provider_id).await,
1198            _ => anyhow::bail!("`llm_provider_models` not available prior to v0.7.0"),
1199        }
1200    }
1201
1202    pub async fn call_llm_provider_is_authenticated(
1203        &self,
1204        store: &mut Store<WasmState>,
1205        provider_id: &str,
1206    ) -> Result<bool> {
1207        match self {
1208            Extension::V0_7_0(ext) => {
1209                ext.call_llm_provider_is_authenticated(store, provider_id)
1210                    .await
1211            }
1212            _ => Ok(false),
1213        }
1214    }
1215
1216    pub async fn call_llm_provider_authenticate(
1217        &self,
1218        store: &mut Store<WasmState>,
1219        provider_id: &str,
1220    ) -> Result<Result<(), String>> {
1221        match self {
1222            Extension::V0_7_0(ext) => ext.call_llm_provider_authenticate(store, provider_id).await,
1223            _ => anyhow::bail!("`llm_provider_authenticate` not available prior to v0.7.0"),
1224        }
1225    }
1226
1227    pub async fn call_llm_provider_reset_credentials(
1228        &self,
1229        store: &mut Store<WasmState>,
1230        provider_id: &str,
1231    ) -> Result<Result<(), String>> {
1232        match self {
1233            Extension::V0_7_0(ext) => {
1234                ext.call_llm_provider_reset_credentials(store, provider_id)
1235                    .await
1236            }
1237            _ => anyhow::bail!("`llm_provider_reset_credentials` not available prior to v0.7.0"),
1238        }
1239    }
1240
1241    pub async fn call_llm_count_tokens(
1242        &self,
1243        store: &mut Store<WasmState>,
1244        provider_id: &str,
1245        model_id: &str,
1246        request: &latest::llm_provider::CompletionRequest,
1247    ) -> Result<Result<u64, String>> {
1248        match self {
1249            Extension::V0_7_0(ext) => {
1250                ext.call_llm_count_tokens(store, provider_id, model_id, request)
1251                    .await
1252            }
1253            _ => anyhow::bail!("`llm_count_tokens` not available prior to v0.7.0"),
1254        }
1255    }
1256
1257    pub async fn call_llm_stream_completion_start(
1258        &self,
1259        store: &mut Store<WasmState>,
1260        provider_id: &str,
1261        model_id: &str,
1262        request: &latest::llm_provider::CompletionRequest,
1263    ) -> Result<Result<String, String>> {
1264        match self {
1265            Extension::V0_7_0(ext) => {
1266                ext.call_llm_stream_completion_start(store, provider_id, model_id, request)
1267                    .await
1268            }
1269            _ => anyhow::bail!("`llm_stream_completion_start` not available prior to v0.7.0"),
1270        }
1271    }
1272
1273    pub async fn call_llm_stream_completion_next(
1274        &self,
1275        store: &mut Store<WasmState>,
1276        stream_id: &str,
1277    ) -> Result<Result<Option<latest::llm_provider::CompletionEvent>, String>> {
1278        match self {
1279            Extension::V0_7_0(ext) => ext.call_llm_stream_completion_next(store, stream_id).await,
1280            _ => anyhow::bail!("`llm_stream_completion_next` not available prior to v0.7.0"),
1281        }
1282    }
1283
1284    pub async fn call_llm_stream_completion_close(
1285        &self,
1286        store: &mut Store<WasmState>,
1287        stream_id: &str,
1288    ) -> Result<()> {
1289        match self {
1290            Extension::V0_7_0(ext) => ext.call_llm_stream_completion_close(store, stream_id).await,
1291            _ => anyhow::bail!("`llm_stream_completion_close` not available prior to v0.7.0"),
1292        }
1293    }
1294
1295    pub async fn call_llm_cache_configuration(
1296        &self,
1297        store: &mut Store<WasmState>,
1298        provider_id: &str,
1299        model_id: &str,
1300    ) -> Result<Option<latest::llm_provider::CacheConfiguration>> {
1301        match self {
1302            Extension::V0_7_0(ext) => {
1303                ext.call_llm_cache_configuration(store, provider_id, model_id)
1304                    .await
1305            }
1306            _ => Ok(None),
1307        }
1308    }
1309}
1310
1311trait ToWasmtimeResult<T> {
1312    fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
1313}
1314
1315impl<T> ToWasmtimeResult<T> for Result<T> {
1316    fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
1317        Ok(self.map_err(|error| format!("{error:?}")))
1318    }
1319}