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