use proc_macro2::TokenStream;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct ElicitToolOutput<T> {
pub value: T,
}
impl<T> ElicitToolOutput<T> {
pub fn new(value: T) -> Self {
Self { value }
}
pub fn into_inner(self) -> T {
self.value
}
}
impl<T> From<T> for ElicitToolOutput<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T> AsRef<T> for ElicitToolOutput<T> {
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T> AsMut<T> for ElicitToolOutput<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T> crate::Prompt for ElicitToolOutput<T> {
fn prompt() -> Option<&'static str> {
Some("Elicit the wrapped value:")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct ElicitToolOutputStyle;
impl crate::Prompt for ElicitToolOutputStyle {
fn prompt() -> Option<&'static str> {
None
}
}
impl crate::Elicitation for ElicitToolOutputStyle {
type Style = ElicitToolOutputStyle;
async fn elicit<C: crate::ElicitCommunicator>(_: &C) -> crate::ElicitResult<Self> {
Ok(Self)
}
fn kani_proof() -> TokenStream {
TokenStream::new()
}
fn verus_proof() -> TokenStream {
TokenStream::new()
}
fn creusot_proof() -> TokenStream {
TokenStream::new()
}
}
impl crate::style::ElicitationStyle for ElicitToolOutputStyle {}
impl crate::ElicitPromptTree for ElicitToolOutputStyle {
fn prompt_tree() -> crate::PromptTree {
crate::PromptTree::Leaf {
prompt: "default".to_string(),
type_name: "ElicitToolOutputStyle".to_string(),
}
}
}
impl<T> crate::Elicitation for ElicitToolOutput<T>
where
T: crate::Elicitation + Send,
{
type Style = ElicitToolOutputStyle;
#[tracing::instrument(skip(communicator))]
async fn elicit<C: crate::ElicitCommunicator>(communicator: &C) -> crate::ElicitResult<Self> {
tracing::debug!("Eliciting ElicitToolOutput<T>");
let value = T::elicit(communicator).await?;
Ok(Self { value })
}
fn kani_proof() -> proc_macro2::TokenStream {
T::kani_proof()
}
fn verus_proof() -> proc_macro2::TokenStream {
T::verus_proof()
}
fn creusot_proof() -> proc_macro2::TokenStream {
T::creusot_proof()
}
}
impl<T: crate::ElicitIntrospect + Send> crate::ElicitIntrospect for ElicitToolOutput<T> {
fn pattern() -> crate::ElicitationPattern {
T::pattern()
}
fn metadata() -> crate::TypeMetadata {
T::metadata()
}
}
impl<T: crate::ElicitPromptTree> crate::ElicitPromptTree for ElicitToolOutput<T> {
fn prompt_tree() -> crate::PromptTree {
T::prompt_tree()
}
}
impl<T: crate::emit_code::ToCodeLiteral> crate::emit_code::ToCodeLiteral for ElicitToolOutput<T> {
fn to_code_literal(&self) -> proc_macro2::TokenStream {
let inner = self.value.to_code_literal();
quote::quote! { elicitation::ElicitToolOutput { value: #inner } }
}
}
impl<T: crate::ElicitSpec + 'static> crate::ElicitSpec for ElicitToolOutput<T> {
fn type_spec() -> crate::TypeSpec {
T::type_spec()
}
}
impl<T> crate::ElicitComplete for ElicitToolOutput<T> where T: crate::ElicitComplete + Send {}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
enum TestEnum {
A,
B,
C,
}
#[test]
fn test_wrapper_construction() {
let wrapped = ElicitToolOutput::new(TestEnum::A);
assert_eq!(wrapped.value, TestEnum::A);
}
#[test]
fn test_wrapper_into_inner() {
let wrapped = ElicitToolOutput::new(42);
assert_eq!(wrapped.into_inner(), 42);
}
#[test]
fn test_wrapper_from() {
let wrapped: ElicitToolOutput<i32> = 42.into();
assert_eq!(wrapped.value, 42);
}
#[test]
fn test_wrapper_as_ref() {
let wrapped = ElicitToolOutput::new(TestEnum::B);
assert_eq!(wrapped.as_ref(), &TestEnum::B);
}
#[test]
fn test_wrapper_serialization() {
let wrapped = ElicitToolOutput::new(TestEnum::C);
let json = serde_json::to_value(&wrapped).expect("Serialize");
assert!(json.is_object());
assert!(json.get("value").is_some());
}
#[test]
fn test_wrapper_schema_is_object() {
use schemars::schema_for;
let schema = schema_for!(ElicitToolOutput<TestEnum>);
assert!(
schema.as_object().is_some(),
"Wrapper schema must be object type"
);
let obj = schema.as_object().unwrap();
assert!(obj.get("properties").is_some());
}
}