use crate::domain::a2a::version::A2aVersion;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Feature {
SendMessage,
SendStreamingMessage,
GetTask,
ListTasks,
CancelTask,
SubscribeToTask,
PushNotificationConfig,
GetExtendedAgentCard,
}
impl Feature {
pub const ALL: [Self; 8] = [
Self::SendMessage,
Self::SendStreamingMessage,
Self::GetTask,
Self::ListTasks,
Self::CancelTask,
Self::SubscribeToTask,
Self::PushNotificationConfig,
Self::GetExtendedAgentCard,
];
pub const fn label(&self) -> &'static str {
match self {
Self::SendMessage => "SendMessage",
Self::SendStreamingMessage => "SendStreamingMessage",
Self::GetTask => "GetTask",
Self::ListTasks => "ListTasks",
Self::CancelTask => "CancelTask",
Self::SubscribeToTask => "SubscribeToTask",
Self::PushNotificationConfig => "PushNotificationConfig",
Self::GetExtendedAgentCard => "GetExtendedAgentCard",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct A2aFeatureProfile {
version: A2aVersion,
bitset: [bool; 8],
}
impl A2aFeatureProfile {
pub const fn for_known_version(version: A2aVersion) -> Self {
match version {
A2aVersion::V1_0 => Self {
version,
bitset: [true; 8],
},
A2aVersion::Unknown { major: _, minor: _ } => Self {
version,
bitset: [false; 8],
},
}
}
pub const fn is_enabled(&self, feature: Feature) -> bool {
match feature {
Feature::SendMessage => self.bitset[0],
Feature::SendStreamingMessage => self.bitset[1],
Feature::GetTask => self.bitset[2],
Feature::ListTasks => self.bitset[3],
Feature::CancelTask => self.bitset[4],
Feature::SubscribeToTask => self.bitset[5],
Feature::PushNotificationConfig => self.bitset[6],
Feature::GetExtendedAgentCard => self.bitset[7],
}
}
pub const fn version(&self) -> A2aVersion {
self.version
}
}
const fn _ensure_feature_match_is_exhaustive(feature: Feature) -> usize {
match feature {
Feature::SendMessage => 0,
Feature::SendStreamingMessage => 1,
Feature::GetTask => 2,
Feature::ListTasks => 3,
Feature::CancelTask => 4,
Feature::SubscribeToTask => 5,
Feature::PushNotificationConfig => 6,
Feature::GetExtendedAgentCard => 7,
}
}
#[cfg(test)]
mod tests {
use super::{A2aFeatureProfile, Feature};
use crate::domain::a2a::version::A2aVersion;
#[test]
fn feature_all_lists_eight_features_in_order() {
assert_eq!(Feature::ALL.len(), 8);
assert_eq!(Feature::ALL[0], Feature::SendMessage);
assert_eq!(Feature::ALL[1], Feature::SendStreamingMessage);
assert_eq!(Feature::ALL[2], Feature::GetTask);
assert_eq!(Feature::ALL[3], Feature::ListTasks);
assert_eq!(Feature::ALL[4], Feature::CancelTask);
assert_eq!(Feature::ALL[5], Feature::SubscribeToTask);
assert_eq!(Feature::ALL[6], Feature::PushNotificationConfig);
assert_eq!(Feature::ALL[7], Feature::GetExtendedAgentCard);
}
#[test]
fn feature_label_is_non_empty_for_every_variant() {
for feature in Feature::ALL {
assert!(
!feature.label().is_empty(),
"{feature:?} has an empty label"
);
}
}
#[test]
fn v1_0_profile_enables_every_feature() {
let profile = A2aFeatureProfile::for_known_version(A2aVersion::V1_0);
for feature in Feature::ALL {
assert!(
profile.is_enabled(feature),
"{feature:?} should be enabled in V1_0"
);
}
}
#[test]
fn unknown_version_profile_disables_every_feature() {
let profile =
A2aFeatureProfile::for_known_version(A2aVersion::Unknown { major: 2, minor: 5 });
for feature in Feature::ALL {
assert!(
!profile.is_enabled(feature),
"{feature:?} should be disabled for an Unknown version"
);
}
}
#[test]
fn is_enabled_returns_the_bit_at_the_feature_index() {
let profile = A2aFeatureProfile::for_known_version(A2aVersion::V1_0);
assert!(profile.is_enabled(Feature::SendMessage));
assert!(profile.is_enabled(Feature::GetExtendedAgentCard));
let unknown =
A2aFeatureProfile::for_known_version(A2aVersion::Unknown { major: 2, minor: 0 });
assert!(!unknown.is_enabled(Feature::SendMessage));
assert!(!unknown.is_enabled(Feature::GetExtendedAgentCard));
}
#[test]
fn version_returns_the_profile_version() {
let v1 = A2aFeatureProfile::for_known_version(A2aVersion::V1_0);
assert_eq!(v1.version(), A2aVersion::V1_0);
let unknown =
A2aFeatureProfile::for_known_version(A2aVersion::Unknown { major: 2, minor: 5 });
assert_eq!(
unknown.version(),
A2aVersion::Unknown { major: 2, minor: 5 }
);
}
}