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