1pub(crate) mod abi;
12pub mod agents;
13pub mod capabilities;
14pub mod code;
15pub mod crypto;
16pub(crate) mod dot_segments;
17pub mod embedding;
18pub mod fs;
19pub mod git;
20pub mod http;
21pub mod llm;
22pub mod secrets;
23pub mod security;
24pub mod session;
25pub mod shared;
26pub mod skills;
27pub mod test;
33pub mod url;
34pub mod uuid;
35pub mod variables;
36
37use wasmtime::Linker;
38
39use crate::runtime::StoreData;
40use crate::{MangledName, PackageDeclaration, Type};
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
49#[non_exhaustive]
50pub enum OptionalPackage {
51 Agents,
53 Skills,
55}
56
57impl OptionalPackage {
58 pub const ALL: &'static [OptionalPackage] = &[Self::Agents, Self::Skills];
59
60 pub const fn module_name(self) -> &'static str {
61 match self {
62 Self::Agents => agents::MODULE_NAME,
63 Self::Skills => skills::MODULE_NAME,
64 }
65 }
66
67 pub fn from_module_name(name: &str) -> Option<Self> {
68 Self::ALL
69 .iter()
70 .copied()
71 .find(|package| package.module_name() == name)
72 }
73
74 fn package_declaration(self) -> PackageDeclaration {
75 match self {
76 Self::Agents => agents::package_declaration(),
77 Self::Skills => skills::package_declaration(),
78 }
79 }
80
81 fn install(self, linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
82 match self {
83 Self::Agents => agents::install(linker),
84 Self::Skills => skills::install(linker),
85 }
86 }
87
88 const fn bit(self) -> u8 {
89 match self {
90 Self::Agents => 1,
91 Self::Skills => 1 << 1,
92 }
93 }
94}
95
96pub(crate) struct SchemaCheckedCall {
101 pub callee: &'static str,
103 pub example: &'static str,
105 pub checks: &'static str,
107 pub answerer: &'static str,
109 pub written_params: &'static str,
111 pub written_param_count: usize,
112 pub untyped_hint: &'static str,
115 pub untyped_hint_for_unknown: &'static str,
117 pub untyped_hint_for_no_schema: &'static str,
119 pub untyped_result: Type,
121}
122
123impl SchemaCheckedCall {
124 pub fn schema_argument_ordinal(&self) -> &'static str {
126 match self.written_param_count {
127 0 => "first",
128 1 => "second",
129 2 => "third",
130 3 => "fourth",
131 _ => "last",
132 }
133 }
134}
135
136pub(crate) fn schema_checked_call(mangled: &MangledName) -> Option<SchemaCheckedCall> {
138 if llm::declaration::is_checked_call(mangled) {
139 return Some(SchemaCheckedCall {
140 callee: "llm.call",
141 example: "llm.call<Severity>(model, prompt)",
142 checks: "the model's response",
143 answerer: "the model",
144 written_params: "the model and the prompt",
145 written_param_count: 2,
146 untyped_hint: "read the `Completion` envelope yourself",
147 untyped_hint_for_unknown: "read the `Completion` envelope's `ok` and `text` yourself",
148 untyped_hint_for_no_schema: "parse the `Completion` text yourself",
149 untyped_result: llm::declaration::untyped_result_type(mangled),
150 });
151 }
152 if agents::declaration::is_checked_run(mangled) {
153 return Some(SchemaCheckedCall {
154 callee: "agents.run",
155 example: "agents.run<Report>(agent, input)",
156 checks: "the agent's result",
157 answerer: "the agent",
158 written_params: "the agent and the input",
159 written_param_count: 2,
160 untyped_hint: "read the returned text yourself",
161 untyped_hint_for_unknown: "read the returned text yourself",
162 untyped_hint_for_no_schema: "parse the returned text yourself",
163 untyped_result: Type::String,
164 });
165 }
166 None
167}
168
169#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
177pub struct Stdlib {
178 optional: u8,
179}
180
181impl Stdlib {
182 pub const fn core() -> Self {
184 Stdlib { optional: 0 }
185 }
186
187 #[must_use]
188 pub const fn with(self, package: OptionalPackage) -> Self {
189 Stdlib {
190 optional: self.optional | package.bit(),
191 }
192 }
193
194 pub const fn enables(self, package: OptionalPackage) -> bool {
195 self.optional & package.bit() != 0
196 }
197
198 pub fn optional_packages(self) -> impl Iterator<Item = OptionalPackage> {
199 OptionalPackage::ALL
200 .iter()
201 .copied()
202 .filter(move |package| self.enables(*package))
203 }
204
205 pub fn contains_module(self, name: &str) -> bool {
207 OptionalPackage::from_module_name(name).map_or_else(
208 || {
209 core_package_declarations()
210 .iter()
211 .any(|defs| defs.package_name == name)
212 },
213 |package| self.enables(package),
214 )
215 }
216
217 pub fn package_declarations(self) -> Vec<PackageDeclaration> {
219 let mut declarations = core_package_declarations();
220 declarations.extend(
221 self.optional_packages()
222 .map(OptionalPackage::package_declaration),
223 );
224 declarations.sort_by(|a, b| a.package_name.cmp(&b.package_name));
226 declarations
227 }
228
229 pub fn install_host_functions(self, linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
230 install_core_host_functions(linker)?;
231 for package in self.optional_packages() {
232 package.install(linker)?;
233 }
234 Ok(())
235 }
236}
237
238pub(crate) fn unavailable_import(module: &str) -> Option<(String, Vec<String>)> {
244 if module == test::MODULE_NAME {
245 return Some((
246 format!("package `{module}` not found"),
247 vec![
248 "`submilli:test` is only available to test files run via `submilli build test`; it is not importable from a program run with `submilli run`"
249 .to_string(),
250 ],
251 ));
252 }
253 let package = OptionalPackage::from_module_name(module)?;
254 Some((
255 format!("package `{module}` is not available in this harness"),
256 vec![format!(
257 "`{}` exists only where the harness running the program provides it",
258 package.module_name()
259 )],
260 ))
261}
262
263pub fn stdlib_package_declarations() -> Vec<PackageDeclaration> {
265 Stdlib::core().package_declarations()
266}
267
268pub fn install_host_functions(linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
269 Stdlib::core().install_host_functions(linker)
270}
271
272fn core_package_declarations() -> Vec<PackageDeclaration> {
273 vec![
274 code::package_declaration(),
276 crypto::package_declaration(),
277 embedding::package_declaration(),
278 fs::package_declaration(),
279 git::package_declaration(),
280 http::package_declaration(),
281 llm::package_declaration(),
282 secrets::package_declaration(),
283 security::package_declaration(),
284 session::package_declaration(),
285 url::package_declaration(),
286 uuid::package_declaration(),
287 variables::package_declaration(),
288 ]
289}
290
291fn install_core_host_functions(linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
292 code::install(linker)?;
293 crypto::install(linker)?;
294 embedding::install(linker)?;
295 fs::install(linker)?;
296 git::install(linker)?;
297 http::install(linker)?;
298 llm::install(linker)?;
299 secrets::install(linker)?;
300 security::install(linker)?;
301 session::install(linker)?;
302 url::install(linker)?;
303 uuid::install(linker)?;
304 variables::install(linker)?;
305 Ok(())
306}
307
308pub(crate) fn install_store_bound(
310 linker: &mut Linker<StoreData>,
311 store: &mut wasmtime::Store<StoreData>,
312) -> wasmtime::Result<()> {
313 git::class::install(linker, store)
314}
315
316#[cfg(test)]
317mod optional_tests;
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322
323 fn every_set() -> Vec<Stdlib> {
325 let mut sets = vec![Stdlib::core()];
326 for package in OptionalPackage::ALL {
327 let with: Vec<Stdlib> = sets.iter().map(|set| set.with(*package)).collect();
328 sets.extend(with);
329 }
330 sets
331 }
332
333 #[test]
334 fn declarations_are_sorted_for_every_set() {
335 for set in every_set() {
336 let names: Vec<String> = set
337 .package_declarations()
338 .into_iter()
339 .map(|defs| defs.package_name)
340 .collect();
341 let mut sorted = names.clone();
342 sorted.sort();
343 assert_eq!(names, sorted, "{set:?}");
344 }
345 }
346
347 #[test]
348 fn a_set_contains_exactly_its_packages() {
349 for set in every_set() {
350 let names: Vec<String> = set
351 .package_declarations()
352 .into_iter()
353 .map(|defs| defs.package_name)
354 .collect();
355 for name in &names {
356 assert!(set.contains_module(name), "{set:?} misses {name}");
357 }
358 for package in OptionalPackage::ALL {
359 assert_eq!(
360 names.iter().any(|name| name == package.module_name()),
361 set.enables(*package),
362 "{set:?} and {package:?}"
363 );
364 }
365 }
366 }
367
368 #[test]
369 fn core_is_the_global_list() {
370 let core: Vec<String> = Stdlib::core()
371 .package_declarations()
372 .into_iter()
373 .map(|defs| defs.package_name)
374 .collect();
375 let global: Vec<String> = stdlib_package_declarations()
376 .into_iter()
377 .map(|defs| defs.package_name)
378 .collect();
379 assert_eq!(core, global);
380 assert!(!Stdlib::core().contains_module(test::MODULE_NAME));
381 }
382}