use crate::ast::TypeExpr;
use harn_builtin_meta::{BuiltinExposure, CapabilityId};
use super::signatures;
use super::{BuiltinMetadata, BuiltinSignature, Ty, TyExt};
pub fn lookup(name: &str) -> Option<&'static BuiltinSignature> {
lookup_with_privileged_wire(name, false)
}
pub fn lookup_with_privileged_wire(
name: &str,
allow_privileged_wire: bool,
) -> Option<&'static BuiltinSignature> {
if let Some(entry) = harn_builtin_registry::builtin_entry(name) {
return matches!(
entry.contract.exposure,
BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
)
.then_some(entry.signature)
.or_else(|| {
(allow_privileged_wire && entry.contract.exposure == BuiltinExposure::PrivilegedWire)
.then_some(entry.signature)
})
.or_else(|| {
(crate::legacy_ambient_capabilities_enabled()
&& matches!(
entry.contract.exposure,
BuiltinExposure::HarnessMethod { .. }
| BuiltinExposure::PrivilegedWire
| BuiltinExposure::RuntimeInternal
))
.then_some(entry.signature)
});
}
if crate::legacy_ambient_capabilities_enabled() {
if let Some(entry) = legacy_capability_method_entry(name) {
return Some(entry.signature);
}
if let Some(entry) = legacy_ambient_cap_global_entry(name) {
return Some(entry.signature);
}
if let Some(canonical) = crate::legacy_builtin_alias_target(name) {
return lookup(canonical);
}
}
for group in signatures::groups() {
for sig in group {
if sig.name == name {
return Some(sig);
}
}
}
None
}
pub fn legacy_capability_method_entry(
name: &str,
) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
let mut matches = ambient_harness_method_entries().filter(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::HarnessMethod { method, .. } if method == name
)
});
let entry = matches.next()?;
matches.next().is_none().then_some(entry)
}
pub fn legacy_ambient_cap_global_entry(
name: &str,
) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
ambient_harness_method_entries().find(|entry| entry.name.strip_prefix("__cap_") == Some(name))
}
pub fn legacy_privileged_wire_entry(
name: &str,
) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
harn_builtin_registry::installed_manifest()
.into_iter()
.find(|entry| {
matches!(entry.contract.exposure, BuiltinExposure::PrivilegedWire)
&& entry.name.strip_prefix("__") == Some(name)
})
}
pub fn legacy_ambient_runtime_name(name: &str) -> Option<&'static str> {
if let Some(target) = crate::legacy_builtin_alias_target(name) {
return Some(target);
}
legacy_privileged_wire_entry(name).map(|entry| entry.name)
}
fn ambient_harness_method_entries(
) -> impl Iterator<Item = &'static harn_builtin_registry::BuiltinManifestEntry> {
harn_builtin_registry::installed_manifest()
.into_iter()
.chain(harn_capability_contracts::manifest().iter().copied())
}
pub fn lookup_capability_method(
capability: CapabilityId,
method: &str,
) -> Option<&'static BuiltinSignature> {
capability_method_entry(capability.field_name(), method).map(|entry| entry.signature)
}
pub fn capability_method_entry(
field: &str,
method: &str,
) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
let capability = CapabilityId::from_field_name(field)?;
harn_builtin_registry::installed_manifest()
.iter()
.copied()
.find(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::HarnessMethod {
capability: candidate,
method: candidate_method,
} if candidate == capability && candidate_method == method
)
})
.or_else(|| harn_capability_contracts::capability_method_entry(field, method))
}
pub fn is_builtin(name: &str) -> bool {
lookup(name).is_some()
|| (crate::legacy_ambient_capabilities_enabled()
&& crate::is_registered_legacy_hostlib_name(name))
}
pub fn is_builtin_with_privileged_wire(name: &str, allow_privileged_wire: bool) -> bool {
lookup_with_privileged_wire(name, allow_privileged_wire).is_some()
|| (crate::legacy_ambient_capabilities_enabled()
&& crate::is_registered_legacy_hostlib_name(name))
}
pub fn iter_builtin_names() -> impl Iterator<Item = &'static str> {
let installed: Vec<_> = harn_builtin_registry::installed_manifest()
.into_iter()
.filter(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
)
})
.collect();
let installed_names: std::collections::HashSet<&'static str> =
harn_builtin_registry::installed_manifest()
.into_iter()
.map(|entry| entry.name)
.collect();
installed.into_iter().map(|entry| entry.name).chain(
signatures::groups()
.into_iter()
.flat_map(|g| g.iter())
.filter(move |s| !installed_names.contains(s.name))
.map(|s| s.name),
)
}
pub fn static_signature_names() -> impl Iterator<Item = &'static str> {
signatures::groups()
.into_iter()
.flat_map(|g| g.iter())
.map(|s| s.name)
}
pub fn iter_builtin_metadata() -> impl Iterator<Item = BuiltinMetadata> {
let installed: Vec<_> = harn_builtin_registry::installed_manifest()
.into_iter()
.filter(|entry| {
matches!(
entry.contract.exposure,
BuiltinExposure::PureGlobal | BuiltinExposure::CapabilityFunction { .. }
)
})
.collect();
let installed_names: std::collections::HashSet<&'static str> =
harn_builtin_registry::installed_manifest()
.into_iter()
.map(|entry| entry.name)
.collect();
installed
.into_iter()
.map(|entry| BuiltinMetadata {
name: entry.name,
return_types: builtin_return_type_names(entry.signature),
})
.chain(
signatures::groups()
.into_iter()
.flat_map(|g| g.iter())
.filter(move |s| !installed_names.contains(s.name))
.map(|sig| BuiltinMetadata {
name: sig.name,
return_types: builtin_return_type_names(sig),
}),
)
}
pub fn builtin_return_type(name: &str) -> Option<TypeExpr> {
let sig = lookup(name)?;
if sig.returns.is_any() {
return None;
}
Some(sig.returns.to_type_expr())
}
pub fn is_untyped_boundary_source(name: &str) -> bool {
matches!(
name,
"json_parse"
| "json_extract"
| "yaml_parse"
| "toml_parse"
| "llm_call"
| "llm_call_safe"
| "llm_completion"
| "http_get"
| "http_post"
| "http_put"
| "http_patch"
| "http_delete"
| "http_download"
| "http_request"
| "http_session_request"
| "http_stream_info"
| "sse_receive"
| "sse_server_mock_receive"
| "sse_server_response"
| "sse_server_status"
| "websocket_accept"
| "websocket_receive"
| "host_call"
| "connector_call"
| "host_tool_call"
)
}
fn builtin_return_type_names(sig: &BuiltinSignature) -> &'static [&'static str] {
match &sig.returns {
Ty::Named(name) => match *name {
"bool" => &["bool"],
"bytes" => &["bytes"],
"dict" => &["dict"],
"float" => &["float"],
"int" => &["int"],
"list" => &["list"],
"nil" => &["nil"],
"string" => &["string"],
_ => &[],
},
Ty::Union(members) => match *members {
[Ty::Named("string"), Ty::Named("nil")] => &["string", "nil"],
[Ty::Named("nil"), Ty::Named("string")] => &["string", "nil"],
[Ty::Named("int"), Ty::Named("nil")] => &["int", "nil"],
[Ty::Named("nil"), Ty::Named("int")] => &["int", "nil"],
[Ty::Named("dict"), Ty::Named("nil")] => &["dict", "nil"],
[Ty::Named("nil"), Ty::Named("dict")] => &["dict", "nil"],
[Ty::Named("bytes"), Ty::Named("nil")] => &["bytes", "nil"],
[Ty::Named("nil"), Ty::Named("bytes")] => &["bytes", "nil"],
_ => &[],
},
Ty::Never => &["never"],
_ => &[],
}
}