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