1use std::fmt;
2use std::sync::Arc;
3
4use agentkit_core::{DataRef, Item, MetadataMap, SessionId, TurnId};
5use async_trait::async_trait;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use thiserror::Error;
9
10macro_rules! capability_id {
11 ($name:ident) => {
12 #[derive(
13 Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
14 )]
15 pub struct $name(pub String);
16
17 impl $name {
18 pub fn new(value: impl Into<String>) -> Self {
19 Self(value.into())
20 }
21 }
22
23 impl fmt::Display for $name {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 self.0.fmt(f)
26 }
27 }
28 };
29}
30
31capability_id!(CapabilityName);
32capability_id!(ResourceId);
33capability_id!(PromptId);
34
35#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
36pub struct InvocableSpec {
37 pub name: CapabilityName,
38 pub description: String,
39 pub input_schema: Value,
40 pub metadata: MetadataMap,
41}
42
43#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
44pub struct InvocableRequest {
45 pub input: Value,
46 pub session_id: Option<SessionId>,
47 pub turn_id: Option<TurnId>,
48 pub metadata: MetadataMap,
49}
50
51#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
52pub struct InvocableResult {
53 pub output: InvocableOutput,
54 pub metadata: MetadataMap,
55}
56
57#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
58pub enum InvocableOutput {
59 Text(String),
60 Structured(Value),
61 Items(Vec<Item>),
62 Data(DataRef),
63}
64
65#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
66pub struct ResourceDescriptor {
67 pub id: ResourceId,
68 pub name: String,
69 pub description: Option<String>,
70 pub mime_type: Option<String>,
71 pub metadata: MetadataMap,
72}
73
74#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
75pub struct ResourceContents {
76 pub data: DataRef,
77 pub metadata: MetadataMap,
78}
79
80#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
81pub struct PromptDescriptor {
82 pub id: PromptId,
83 pub name: String,
84 pub description: Option<String>,
85 pub input_schema: Value,
86 pub metadata: MetadataMap,
87}
88
89#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
90pub struct PromptContents {
91 pub items: Vec<Item>,
92 pub metadata: MetadataMap,
93}
94
95#[derive(Clone, Debug, PartialEq, Eq)]
96pub struct CapabilityContext<'a> {
97 pub session_id: Option<&'a SessionId>,
98 pub turn_id: Option<&'a TurnId>,
99 pub metadata: &'a MetadataMap,
100}
101
102#[async_trait]
103pub trait Invocable: Send + Sync {
104 fn spec(&self) -> &InvocableSpec;
105
106 async fn invoke(
107 &self,
108 request: InvocableRequest,
109 ctx: &mut CapabilityContext<'_>,
110 ) -> Result<InvocableResult, CapabilityError>;
111}
112
113#[async_trait]
114pub trait ResourceProvider: Send + Sync {
115 async fn list_resources(&self) -> Result<Vec<ResourceDescriptor>, CapabilityError>;
116
117 async fn read_resource(
118 &self,
119 id: &ResourceId,
120 ctx: &mut CapabilityContext<'_>,
121 ) -> Result<ResourceContents, CapabilityError>;
122}
123
124#[async_trait]
125pub trait PromptProvider: Send + Sync {
126 async fn list_prompts(&self) -> Result<Vec<PromptDescriptor>, CapabilityError>;
127
128 async fn get_prompt(
129 &self,
130 id: &PromptId,
131 args: Value,
132 ctx: &mut CapabilityContext<'_>,
133 ) -> Result<PromptContents, CapabilityError>;
134}
135
136pub trait CapabilityProvider: Send + Sync {
137 fn invocables(&self) -> Vec<Arc<dyn Invocable>>;
138 fn resources(&self) -> Vec<Arc<dyn ResourceProvider>>;
139 fn prompts(&self) -> Vec<Arc<dyn PromptProvider>>;
140}
141
142#[derive(Debug, Error)]
143pub enum CapabilityError {
144 #[error("capability unavailable: {0}")]
145 Unavailable(String),
146 #[error("invalid capability input: {0}")]
147 InvalidInput(String),
148 #[error("capability execution failed: {0}")]
149 ExecutionFailed(String),
150}