1//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
2
3pub mod http_client;
4pub mod process;
5pub mod settings;
6
7use core::fmt;
8
9use wit::*;
10
11pub use serde_json;
12
13// WIT re-exports.
14//
15// We explicitly enumerate the symbols we want to re-export, as there are some
16// that we may want to shadow to provide a cleaner Rust API.
17pub use wit::{
18 CodeLabel, CodeLabelSpan, CodeLabelSpanLiteral, Command, DownloadedFileType, EnvVars,
19 KeyValueStore, LanguageServerInstallationStatus, Project, Range, Worktree, download_file,
20 make_file_executable,
21 zed::extension::context_server::ContextServerConfiguration,
22 zed::extension::dap::{
23 AttachRequest, BuildTaskDefinition, BuildTaskDefinitionTemplatePayload, BuildTaskTemplate,
24 DebugAdapterBinary, DebugConfig, DebugRequest, DebugScenario, DebugTaskDefinition,
25 LaunchRequest, StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
26 TaskTemplate, TcpArguments, TcpArgumentsTemplate, resolve_tcp_template,
27 },
28 zed::extension::github::{
29 GithubRelease, GithubReleaseAsset, GithubReleaseOptions, github_release_by_tag_name,
30 latest_github_release,
31 },
32 zed::extension::llm_provider::{
33 CacheConfiguration as LlmCacheConfiguration, CompletionEvent as LlmCompletionEvent,
34 CompletionRequest as LlmCompletionRequest, CredentialType as LlmCredentialType,
35 ImageData as LlmImageData, MessageContent as LlmMessageContent,
36 MessageRole as LlmMessageRole, ModelCapabilities as LlmModelCapabilities,
37 ModelInfo as LlmModelInfo, OauthHttpRequest as LlmOauthHttpRequest,
38 OauthHttpResponse as LlmOauthHttpResponse, OauthWebAuthConfig as LlmOauthWebAuthConfig,
39 OauthWebAuthResult as LlmOauthWebAuthResult, ProviderInfo as LlmProviderInfo,
40 RequestMessage as LlmRequestMessage, StopReason as LlmStopReason,
41 ThinkingContent as LlmThinkingContent, TokenUsage as LlmTokenUsage,
42 ToolChoice as LlmToolChoice, ToolDefinition as LlmToolDefinition,
43 ToolInputFormat as LlmToolInputFormat, ToolResult as LlmToolResult,
44 ToolResultContent as LlmToolResultContent, ToolUse as LlmToolUse,
45 ToolUseJsonParseError as LlmToolUseJsonParseError,
46 delete_credential as llm_delete_credential, get_credential as llm_get_credential,
47 get_env_var as llm_get_env_var, oauth_open_browser as llm_oauth_open_browser,
48 oauth_start_web_auth as llm_oauth_start_web_auth,
49 request_credential as llm_request_credential,
50 send_oauth_http_request as llm_oauth_http_request,
51 store_credential as llm_store_credential,
52 },
53 zed::extension::nodejs::{
54 node_binary_path, npm_install_package, npm_package_installed_version,
55 npm_package_latest_version,
56 },
57 zed::extension::platform::{Architecture, Os, current_platform},
58 zed::extension::slash_command::{
59 SlashCommand, SlashCommandArgumentCompletion, SlashCommandOutput, SlashCommandOutputSection,
60 },
61};
62
63// Undocumented WIT re-exports.
64//
65// These are symbols that need to be public for the purposes of implementing
66// the extension host, but aren't relevant to extension authors.
67#[doc(hidden)]
68pub use wit::Guest;
69
70/// Constructs for interacting with language servers over the
71/// Language Server Protocol (LSP).
72pub mod lsp {
73 pub use crate::wit::zed::extension::lsp::{
74 Completion, CompletionKind, InsertTextFormat, Symbol, SymbolKind,
75 };
76}
77
78/// A result returned from a Zed extension.
79pub type Result<T, E = String> = core::result::Result<T, E>;
80
81/// Updates the installation status for the given language server.
82pub fn set_language_server_installation_status(
83 language_server_id: &LanguageServerId,
84 status: &LanguageServerInstallationStatus,
85) {
86 wit::set_language_server_installation_status(&language_server_id.0, status)
87}
88
89/// A Zed extension.
90pub trait Extension: Send + Sync {
91 /// Returns a new instance of the extension.
92 fn new() -> Self
93 where
94 Self: Sized;
95
96 /// Returns the command used to start the language server for the specified
97 /// language.
98 fn language_server_command(
99 &mut self,
100 _language_server_id: &LanguageServerId,
101 _worktree: &Worktree,
102 ) -> Result<Command> {
103 Err("`language_server_command` not implemented".to_string())
104 }
105
106 /// Returns the initialization options to pass to the specified language server.
107 fn language_server_initialization_options(
108 &mut self,
109 _language_server_id: &LanguageServerId,
110 _worktree: &Worktree,
111 ) -> Result<Option<serde_json::Value>> {
112 Ok(None)
113 }
114
115 /// Returns the workspace configuration options to pass to the language server.
116 fn language_server_workspace_configuration(
117 &mut self,
118 _language_server_id: &LanguageServerId,
119 _worktree: &Worktree,
120 ) -> Result<Option<serde_json::Value>> {
121 Ok(None)
122 }
123
124 /// Returns the initialization options to pass to the other language server.
125 fn language_server_additional_initialization_options(
126 &mut self,
127 _language_server_id: &LanguageServerId,
128 _target_language_server_id: &LanguageServerId,
129 _worktree: &Worktree,
130 ) -> Result<Option<serde_json::Value>> {
131 Ok(None)
132 }
133
134 /// Returns the workspace configuration options to pass to the other language server.
135 fn language_server_additional_workspace_configuration(
136 &mut self,
137 _language_server_id: &LanguageServerId,
138 _target_language_server_id: &LanguageServerId,
139 _worktree: &Worktree,
140 ) -> Result<Option<serde_json::Value>> {
141 Ok(None)
142 }
143
144 /// Returns the label for the given completion.
145 fn label_for_completion(
146 &self,
147 _language_server_id: &LanguageServerId,
148 _completion: Completion,
149 ) -> Option<CodeLabel> {
150 None
151 }
152
153 /// Returns the label for the given symbol.
154 fn label_for_symbol(
155 &self,
156 _language_server_id: &LanguageServerId,
157 _symbol: Symbol,
158 ) -> Option<CodeLabel> {
159 None
160 }
161
162 /// Returns the completions that should be shown when completing the provided slash command with the given query.
163 fn complete_slash_command_argument(
164 &self,
165 _command: SlashCommand,
166 _args: Vec<String>,
167 ) -> Result<Vec<SlashCommandArgumentCompletion>, String> {
168 Ok(Vec::new())
169 }
170
171 /// Returns the output from running the provided slash command.
172 fn run_slash_command(
173 &self,
174 _command: SlashCommand,
175 _args: Vec<String>,
176 _worktree: Option<&Worktree>,
177 ) -> Result<SlashCommandOutput, String> {
178 Err("`run_slash_command` not implemented".to_string())
179 }
180
181 /// Returns the command used to start a context server.
182 fn context_server_command(
183 &mut self,
184 _context_server_id: &ContextServerId,
185 _project: &Project,
186 ) -> Result<Command> {
187 Err("`context_server_command` not implemented".to_string())
188 }
189
190 /// Returns the configuration options for the specified context server.
191 fn context_server_configuration(
192 &mut self,
193 _context_server_id: &ContextServerId,
194 _project: &Project,
195 ) -> Result<Option<ContextServerConfiguration>> {
196 Ok(None)
197 }
198
199 /// Returns a list of package names as suggestions to be included in the
200 /// search results of the `/docs` slash command.
201 ///
202 /// This can be used to provide completions for known packages (e.g., from the
203 /// local project or a registry) before a package has been indexed.
204 fn suggest_docs_packages(&self, _provider: String) -> Result<Vec<String>, String> {
205 Ok(Vec::new())
206 }
207
208 /// Indexes the docs for the specified package.
209 fn index_docs(
210 &self,
211 _provider: String,
212 _package: String,
213 _database: &KeyValueStore,
214 ) -> Result<(), String> {
215 Err("`index_docs` not implemented".to_string())
216 }
217
218 /// Returns the debug adapter binary for the specified adapter name and configuration.
219 fn get_dap_binary(
220 &mut self,
221 _adapter_name: String,
222 _config: DebugTaskDefinition,
223 _user_provided_debug_adapter_path: Option<String>,
224 _worktree: &Worktree,
225 ) -> Result<DebugAdapterBinary, String> {
226 Err("`get_dap_binary` not implemented".to_string())
227 }
228
229 /// Determines whether the specified adapter configuration should *launch* a new debuggee process
230 /// or *attach* to an existing one. This function should not perform any further validation (outside of determining the kind of a request).
231 /// This function should return an error when the kind cannot be determined (rather than fall back to a known default).
232 fn dap_request_kind(
233 &mut self,
234 _adapter_name: String,
235 _config: serde_json::Value,
236 ) -> Result<StartDebuggingRequestArgumentsRequest, String> {
237 Err("`dap_request_kind` not implemented".to_string())
238 }
239 /// Converts a high-level definition of a debug scenario (originating in a new session UI) to a "low-level" configuration suitable for a particular adapter.
240 ///
241 /// In layman's terms: given a program, list of arguments, current working directory and environment variables,
242 /// create a configuration that can be used to start a debug session.
243 fn dap_config_to_scenario(&mut self, _config: DebugConfig) -> Result<DebugScenario, String> {
244 Err("`dap_config_to_scenario` not implemented".to_string())
245 }
246
247 /// Locators are entities that convert a Zed task into a debug scenario.
248 ///
249 /// They can be provided even by extensions that don't provide a debug adapter.
250 /// For all tasks applicable to a given buffer, Zed will query all locators to find one that can turn the task into a debug scenario.
251 /// A converted debug scenario can include a build task (it shouldn't contain any configuration in such case); a build task result will later
252 /// be resolved with [`Extension::run_dap_locator`].
253 ///
254 /// To work through a real-world example, take a `cargo run` task and a hypothetical `cargo` locator:
255 /// 1. We may need to modify the task; in this case, it is problematic that `cargo run` spawns a binary. We should turn `cargo run` into a debug scenario with
256 /// `cargo build` task. This is the decision we make at `dap_locator_create_scenario` scope.
257 /// 2. Then, after the build task finishes, we will run `run_dap_locator` of the locator that produced the build task to find the program to be debugged. This function
258 /// should give us a debugger-agnostic configuration for launching a debug target (that we end up resolving with [`Extension::dap_config_to_scenario`]). It's almost as if the user
259 /// found the artifact path by themselves.
260 ///
261 /// Note that you're not obliged to use build tasks with locators. Specifically, it is sufficient to provide a debug configuration directly in the return value of
262 /// `dap_locator_create_scenario` if you're able to do that. Make sure to not fill out `build` field in that case, as that will prevent Zed from running second phase of resolution in such case.
263 /// This might be of particular relevance to interpreted languages.
264 fn dap_locator_create_scenario(
265 &mut self,
266 _locator_name: String,
267 _build_task: TaskTemplate,
268 _resolved_label: String,
269 _debug_adapter_name: String,
270 ) -> Option<DebugScenario> {
271 None
272 }
273
274 /// Runs the second phase of locator resolution.
275 /// See [`Extension::dap_locator_create_scenario`] for a hefty comment on locators.
276 fn run_dap_locator(
277 &mut self,
278 _locator_name: String,
279 _build_task: TaskTemplate,
280 ) -> Result<DebugRequest, String> {
281 Err("`run_dap_locator` not implemented".to_string())
282 }
283
284 /// Returns information about language model providers offered by this extension.
285 fn llm_providers(&self) -> Vec<LlmProviderInfo> {
286 Vec::new()
287 }
288
289 /// Returns the models available for a provider.
290 fn llm_provider_models(&self, _provider_id: &str) -> Result<Vec<LlmModelInfo>, String> {
291 Ok(Vec::new())
292 }
293
294 /// Returns markdown content to display in the provider's settings UI.
295 /// This can include setup instructions, links to documentation, etc.
296 fn llm_provider_settings_markdown(&self, _provider_id: &str) -> Option<String> {
297 None
298 }
299
300 /// Check if the provider is authenticated.
301 fn llm_provider_is_authenticated(&self, _provider_id: &str) -> bool {
302 false
303 }
304
305 /// Attempt to authenticate the provider.
306 /// This is called for background credential checks - it should check for
307 /// existing credentials and return Ok if found, or an error if not.
308 fn llm_provider_authenticate(&mut self, _provider_id: &str) -> Result<(), String> {
309 Err("`llm_provider_authenticate` not implemented".to_string())
310 }
311
312 /// Start an OAuth device flow sign-in.
313 /// This is called when the user explicitly clicks "Sign in with GitHub" or similar.
314 /// Opens the browser to the verification URL and returns the user code that should
315 /// be displayed to the user.
316 fn llm_provider_start_device_flow_sign_in(
317 &mut self,
318 _provider_id: &str,
319 ) -> Result<String, String> {
320 Err("`llm_provider_start_device_flow_sign_in` not implemented".to_string())
321 }
322
323 /// Poll for device flow sign-in completion.
324 /// This is called after llm_provider_start_device_flow_sign_in returns the user code.
325 /// The extension should poll the OAuth provider until the user authorizes or the flow times out.
326 fn llm_provider_poll_device_flow_sign_in(&mut self, _provider_id: &str) -> Result<(), String> {
327 Err("`llm_provider_poll_device_flow_sign_in` not implemented".to_string())
328 }
329
330 /// Reset credentials for the provider.
331 fn llm_provider_reset_credentials(&mut self, _provider_id: &str) -> Result<(), String> {
332 Err("`llm_provider_reset_credentials` not implemented".to_string())
333 }
334
335 /// Count tokens for a request.
336 fn llm_count_tokens(
337 &self,
338 _provider_id: &str,
339 _model_id: &str,
340 _request: &LlmCompletionRequest,
341 ) -> Result<u64, String> {
342 Err("`llm_count_tokens` not implemented".to_string())
343 }
344
345 /// Start streaming a completion from the model.
346 /// Returns a stream ID that can be used with `llm_stream_completion_next` and `llm_stream_completion_close`.
347 fn llm_stream_completion_start(
348 &mut self,
349 _provider_id: &str,
350 _model_id: &str,
351 _request: &LlmCompletionRequest,
352 ) -> Result<String, String> {
353 Err("`llm_stream_completion_start` not implemented".to_string())
354 }
355
356 /// Get the next event from a completion stream.
357 /// Returns `Ok(None)` when the stream is complete.
358 fn llm_stream_completion_next(
359 &mut self,
360 _stream_id: &str,
361 ) -> Result<Option<LlmCompletionEvent>, String> {
362 Err("`llm_stream_completion_next` not implemented".to_string())
363 }
364
365 /// Close a completion stream and release its resources.
366 fn llm_stream_completion_close(&mut self, _stream_id: &str) {
367 // Default implementation does nothing
368 }
369
370 /// Get cache configuration for a model (if prompt caching is supported).
371 fn llm_cache_configuration(
372 &self,
373 _provider_id: &str,
374 _model_id: &str,
375 ) -> Option<LlmCacheConfiguration> {
376 None
377 }
378}
379
380/// Registers the provided type as a Zed extension.
381///
382/// The type must implement the [`Extension`] trait.
383#[macro_export]
384macro_rules! register_extension {
385 ($extension_type:ty) => {
386 #[cfg(target_os = "wasi")]
387 mod wasi_ext {
388 unsafe extern "C" {
389 static mut errno: i32;
390 pub static mut __wasilibc_cwd: *mut std::ffi::c_char;
391 }
392
393 pub fn init_cwd() {
394 unsafe {
395 // Ensure that our chdir function is linked, instead of the
396 // one from wasi-libc in the chdir.o translation unit. Otherwise
397 // we risk linking in `__wasilibc_find_relpath_alloc` which
398 // is a weak symbol and is being used by
399 // `__wasilibc_find_relpath`, which we do not want on
400 // Windows.
401 chdir(std::ptr::null());
402
403 __wasilibc_cwd = std::ffi::CString::new(std::env::var("PWD").unwrap())
404 .unwrap()
405 .into_raw()
406 .cast();
407 }
408 }
409
410 #[unsafe(no_mangle)]
411 pub unsafe extern "C" fn chdir(raw_path: *const std::ffi::c_char) -> i32 {
412 // Forbid extensions from changing CWD and so return an appropriate error code.
413 errno = 58; // NOTSUP
414 return -1;
415 }
416 }
417
418 #[unsafe(export_name = "init-extension")]
419 pub extern "C" fn __init_extension() {
420 #[cfg(target_os = "wasi")]
421 wasi_ext::init_cwd();
422
423 zed_extension_api::register_extension(|| {
424 Box::new(<$extension_type as zed_extension_api::Extension>::new())
425 });
426 }
427 };
428}
429
430#[doc(hidden)]
431pub fn register_extension(build_extension: fn() -> Box<dyn Extension>) {
432 unsafe { EXTENSION = Some((build_extension)()) }
433}
434
435fn extension() -> &'static mut dyn Extension {
436 #[expect(static_mut_refs)]
437 unsafe {
438 EXTENSION.as_deref_mut().unwrap()
439 }
440}
441
442static mut EXTENSION: Option<Box<dyn Extension>> = None;
443
444#[cfg(target_arch = "wasm32")]
445#[unsafe(link_section = "zed:api-version")]
446#[doc(hidden)]
447pub static ZED_API_VERSION: [u8; 6] = *include_bytes!(concat!(env!("OUT_DIR"), "/version_bytes"));
448
449mod wit {
450
451 wit_bindgen::generate!({
452 skip: ["init-extension"],
453 path: "./wit/since_v0.8.0",
454 });
455}
456
457wit::export!(Component);
458
459struct Component;
460
461impl wit::Guest for Component {
462 fn language_server_command(
463 language_server_id: String,
464 worktree: &wit::Worktree,
465 ) -> Result<wit::Command> {
466 let language_server_id = LanguageServerId(language_server_id);
467 extension().language_server_command(&language_server_id, worktree)
468 }
469
470 fn language_server_initialization_options(
471 language_server_id: String,
472 worktree: &Worktree,
473 ) -> Result<Option<String>, String> {
474 let language_server_id = LanguageServerId(language_server_id);
475 Ok(extension()
476 .language_server_initialization_options(&language_server_id, worktree)?
477 .and_then(|value| serde_json::to_string(&value).ok()))
478 }
479
480 fn language_server_workspace_configuration(
481 language_server_id: String,
482 worktree: &Worktree,
483 ) -> Result<Option<String>, String> {
484 let language_server_id = LanguageServerId(language_server_id);
485 Ok(extension()
486 .language_server_workspace_configuration(&language_server_id, worktree)?
487 .and_then(|value| serde_json::to_string(&value).ok()))
488 }
489
490 fn language_server_additional_initialization_options(
491 language_server_id: String,
492 target_language_server_id: String,
493 worktree: &Worktree,
494 ) -> Result<Option<String>, String> {
495 let language_server_id = LanguageServerId(language_server_id);
496 let target_language_server_id = LanguageServerId(target_language_server_id);
497 Ok(extension()
498 .language_server_additional_initialization_options(
499 &language_server_id,
500 &target_language_server_id,
501 worktree,
502 )?
503 .and_then(|value| serde_json::to_string(&value).ok()))
504 }
505
506 fn language_server_additional_workspace_configuration(
507 language_server_id: String,
508 target_language_server_id: String,
509 worktree: &Worktree,
510 ) -> Result<Option<String>, String> {
511 let language_server_id = LanguageServerId(language_server_id);
512 let target_language_server_id = LanguageServerId(target_language_server_id);
513 Ok(extension()
514 .language_server_additional_workspace_configuration(
515 &language_server_id,
516 &target_language_server_id,
517 worktree,
518 )?
519 .and_then(|value| serde_json::to_string(&value).ok()))
520 }
521
522 fn labels_for_completions(
523 language_server_id: String,
524 completions: Vec<Completion>,
525 ) -> Result<Vec<Option<CodeLabel>>, String> {
526 let language_server_id = LanguageServerId(language_server_id);
527 let mut labels = Vec::new();
528 for (ix, completion) in completions.into_iter().enumerate() {
529 let label = extension().label_for_completion(&language_server_id, completion);
530 if let Some(label) = label {
531 labels.resize(ix + 1, None);
532 *labels.last_mut().unwrap() = Some(label);
533 }
534 }
535 Ok(labels)
536 }
537
538 fn labels_for_symbols(
539 language_server_id: String,
540 symbols: Vec<Symbol>,
541 ) -> Result<Vec<Option<CodeLabel>>, String> {
542 let language_server_id = LanguageServerId(language_server_id);
543 let mut labels = Vec::new();
544 for (ix, symbol) in symbols.into_iter().enumerate() {
545 let label = extension().label_for_symbol(&language_server_id, symbol);
546 if let Some(label) = label {
547 labels.resize(ix + 1, None);
548 *labels.last_mut().unwrap() = Some(label);
549 }
550 }
551 Ok(labels)
552 }
553
554 fn complete_slash_command_argument(
555 command: SlashCommand,
556 args: Vec<String>,
557 ) -> Result<Vec<SlashCommandArgumentCompletion>, String> {
558 extension().complete_slash_command_argument(command, args)
559 }
560
561 fn run_slash_command(
562 command: SlashCommand,
563 args: Vec<String>,
564 worktree: Option<&Worktree>,
565 ) -> Result<SlashCommandOutput, String> {
566 extension().run_slash_command(command, args, worktree)
567 }
568
569 fn context_server_command(
570 context_server_id: String,
571 project: &Project,
572 ) -> Result<wit::Command> {
573 let context_server_id = ContextServerId(context_server_id);
574 extension().context_server_command(&context_server_id, project)
575 }
576
577 fn context_server_configuration(
578 context_server_id: String,
579 project: &Project,
580 ) -> Result<Option<ContextServerConfiguration>, String> {
581 let context_server_id = ContextServerId(context_server_id);
582 extension().context_server_configuration(&context_server_id, project)
583 }
584
585 fn suggest_docs_packages(provider: String) -> Result<Vec<String>, String> {
586 extension().suggest_docs_packages(provider)
587 }
588
589 fn index_docs(
590 provider: String,
591 package: String,
592 database: &KeyValueStore,
593 ) -> Result<(), String> {
594 extension().index_docs(provider, package, database)
595 }
596
597 fn get_dap_binary(
598 adapter_name: String,
599 config: DebugTaskDefinition,
600 user_installed_path: Option<String>,
601 worktree: &Worktree,
602 ) -> Result<wit::DebugAdapterBinary, String> {
603 extension().get_dap_binary(adapter_name, config, user_installed_path, worktree)
604 }
605
606 fn dap_request_kind(
607 adapter_name: String,
608 config: String,
609 ) -> Result<StartDebuggingRequestArgumentsRequest, String> {
610 extension().dap_request_kind(
611 adapter_name,
612 serde_json::from_str(&config).map_err(|e| format!("Failed to parse config: {e}"))?,
613 )
614 }
615 fn dap_config_to_scenario(config: DebugConfig) -> Result<DebugScenario, String> {
616 extension().dap_config_to_scenario(config)
617 }
618 fn dap_locator_create_scenario(
619 locator_name: String,
620 build_task: TaskTemplate,
621 resolved_label: String,
622 debug_adapter_name: String,
623 ) -> Option<DebugScenario> {
624 extension().dap_locator_create_scenario(
625 locator_name,
626 build_task,
627 resolved_label,
628 debug_adapter_name,
629 )
630 }
631 fn run_dap_locator(
632 locator_name: String,
633 build_task: TaskTemplate,
634 ) -> Result<DebugRequest, String> {
635 extension().run_dap_locator(locator_name, build_task)
636 }
637
638 fn llm_providers() -> Vec<LlmProviderInfo> {
639 extension().llm_providers()
640 }
641
642 fn llm_provider_models(provider_id: String) -> Result<Vec<LlmModelInfo>, String> {
643 extension().llm_provider_models(&provider_id)
644 }
645
646 fn llm_provider_settings_markdown(provider_id: String) -> Option<String> {
647 extension().llm_provider_settings_markdown(&provider_id)
648 }
649
650 fn llm_provider_is_authenticated(provider_id: String) -> bool {
651 extension().llm_provider_is_authenticated(&provider_id)
652 }
653
654 fn llm_provider_authenticate(provider_id: String) -> Result<(), String> {
655 extension().llm_provider_authenticate(&provider_id)
656 }
657
658 fn llm_provider_start_device_flow_sign_in(provider_id: String) -> Result<String, String> {
659 extension().llm_provider_start_device_flow_sign_in(&provider_id)
660 }
661
662 fn llm_provider_poll_device_flow_sign_in(provider_id: String) -> Result<(), String> {
663 extension().llm_provider_poll_device_flow_sign_in(&provider_id)
664 }
665
666 fn llm_provider_reset_credentials(provider_id: String) -> Result<(), String> {
667 extension().llm_provider_reset_credentials(&provider_id)
668 }
669
670 fn llm_count_tokens(
671 provider_id: String,
672 model_id: String,
673 request: LlmCompletionRequest,
674 ) -> Result<u64, String> {
675 extension().llm_count_tokens(&provider_id, &model_id, &request)
676 }
677
678 fn llm_stream_completion_start(
679 provider_id: String,
680 model_id: String,
681 request: LlmCompletionRequest,
682 ) -> Result<String, String> {
683 extension().llm_stream_completion_start(&provider_id, &model_id, &request)
684 }
685
686 fn llm_stream_completion_next(stream_id: String) -> Result<Option<LlmCompletionEvent>, String> {
687 extension().llm_stream_completion_next(&stream_id)
688 }
689
690 fn llm_stream_completion_close(stream_id: String) {
691 extension().llm_stream_completion_close(&stream_id)
692 }
693
694 fn llm_cache_configuration(
695 provider_id: String,
696 model_id: String,
697 ) -> Option<LlmCacheConfiguration> {
698 extension().llm_cache_configuration(&provider_id, &model_id)
699 }
700}
701
702/// The ID of a language server.
703#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
704pub struct LanguageServerId(String);
705
706impl AsRef<str> for LanguageServerId {
707 fn as_ref(&self) -> &str {
708 &self.0
709 }
710}
711
712impl fmt::Display for LanguageServerId {
713 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
714 write!(f, "{}", self.0)
715 }
716}
717
718/// The ID of a context server.
719#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
720pub struct ContextServerId(String);
721
722impl AsRef<str> for ContextServerId {
723 fn as_ref(&self) -> &str {
724 &self.0
725 }
726}
727
728impl fmt::Display for ContextServerId {
729 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730 write!(f, "{}", self.0)
731 }
732}
733
734impl CodeLabelSpan {
735 /// Returns a [`CodeLabelSpan::CodeRange`].
736 pub fn code_range(range: impl Into<wit::Range>) -> Self {
737 Self::CodeRange(range.into())
738 }
739
740 /// Returns a [`CodeLabelSpan::Literal`].
741 pub fn literal(text: impl Into<String>, highlight_name: Option<String>) -> Self {
742 Self::Literal(CodeLabelSpanLiteral {
743 text: text.into(),
744 highlight_name,
745 })
746 }
747}
748
749impl From<std::ops::Range<u32>> for wit::Range {
750 fn from(value: std::ops::Range<u32>) -> Self {
751 Self {
752 start: value.start,
753 end: value.end,
754 }
755 }
756}
757
758impl From<std::ops::Range<usize>> for wit::Range {
759 fn from(value: std::ops::Range<usize>) -> Self {
760 Self {
761 start: value.start as u32,
762 end: value.end as u32,
763 }
764 }
765}