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}