use alloc::{collections::BTreeMap, string::String, vec::Vec};
use crate::{AllowList, NetworkPolicy, SecretRequirement};
#[cfg(feature = "schemars")]
use schemars::JsonSchema;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct Capabilities {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub http: Option<HttpCaps>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub secrets: Option<SecretsCaps>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub kv: Option<KvCaps>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub fs: Option<FsCaps>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub net: Option<NetCaps>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub tools: Option<ToolsCaps>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub auth: Option<AuthCaps>,
}
impl Capabilities {
pub fn new() -> Self {
Self::default()
}
pub fn is_empty(&self) -> bool {
self.http.is_none()
&& self.secrets.is_none()
&& self.kv.is_none()
&& self.fs.is_none()
&& self.net.is_none()
&& self.tools.is_none()
&& self.auth.is_none()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct AuthCaps {
#[cfg_attr(feature = "serde", serde(default))]
pub kind: AuthKind,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub oauth: Option<OAuthSpec>,
}
impl AuthCaps {
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub enum AuthKind {
#[default]
None,
ApiKey,
#[cfg_attr(feature = "serde", serde(rename = "oauth"))]
OAuth,
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct OAuthSpec {
pub authorize_url: String,
pub token_url: String,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub scopes: Vec<String>,
#[cfg_attr(feature = "serde", serde(default))]
pub pkce: bool,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "BTreeMap::is_empty")
)]
pub extra_auth_params: BTreeMap<String, String>,
#[cfg_attr(feature = "serde", serde(default))]
pub token_auth_style: TokenAuthStyle,
}
impl OAuthSpec {
pub fn new(authorize_url: impl Into<String>, token_url: impl Into<String>) -> Self {
Self {
authorize_url: authorize_url.into(),
token_url: token_url.into(),
scopes: Vec::new(),
pkce: false,
extra_auth_params: BTreeMap::new(),
token_auth_style: TokenAuthStyle::Basic,
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub enum TokenAuthStyle {
#[default]
Basic,
Body,
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct HttpCaps {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub allow_list: Option<AllowList>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub max_body_bytes: Option<u64>,
}
impl HttpCaps {
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct SecretsCaps {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub required: Vec<SecretRequirement>,
}
impl SecretsCaps {
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct KvCaps {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub namespaces: Vec<String>,
}
impl KvCaps {
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct FsCaps {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub paths: Vec<String>,
#[cfg_attr(feature = "serde", serde(default = "FsCaps::default_read_only"))]
pub read_only: bool,
}
impl Default for FsCaps {
fn default() -> Self {
Self {
paths: Vec::new(),
read_only: true,
}
}
}
impl FsCaps {
const fn default_read_only() -> bool {
true
}
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct NetCaps {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub policy: Option<NetworkPolicy>,
}
impl NetCaps {
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct ToolsCaps {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Vec::is_empty")
)]
pub allowed: Vec<String>,
}
impl ToolsCaps {
pub fn new() -> Self {
Self::default()
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct Limits {
pub memory_mb: u32,
pub wall_time_ms: u64,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub fuel: Option<u64>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub files: Option<u32>,
}
impl Limits {
pub fn new(memory_mb: u32, wall_time_ms: u64) -> Self {
Self {
memory_mb,
wall_time_ms,
fuel: None,
files: None,
}
}
}
impl Default for Limits {
fn default() -> Self {
Self::new(0, 0)
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct TelemetrySpec {
pub span_prefix: String,
#[cfg_attr(feature = "serde", serde(default))]
pub attributes: BTreeMap<String, String>,
pub emit_node_spans: bool,
}
impl TelemetrySpec {
pub fn new(span_prefix: impl Into<String>) -> Self {
Self {
span_prefix: span_prefix.into(),
attributes: BTreeMap::new(),
emit_node_spans: false,
}
}
}
impl Default for TelemetrySpec {
fn default() -> Self {
Self::new("greentic")
}
}