Skip to main content

cedros_data/http_discovery/
types.rs

1//! Shared types for AI discovery endpoints
2
3use serde::Serialize;
4
5// ============================================================================
6// Skill Metadata (skill.json)
7// ============================================================================
8
9#[derive(Debug, Serialize)]
10#[serde(rename_all = "camelCase")]
11pub struct SkillMetadata {
12    pub name: String,
13    pub version: String,
14    pub description: String,
15    pub homepage: Option<String>,
16    pub api_base: String,
17    pub category: String,
18    pub capabilities: SkillCapabilities,
19    pub skills: Vec<SkillReference>,
20    pub authentication: SkillAuth,
21    pub rate_limits: RateLimits,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub downloadable_bundles: Option<DownloadableBundles>,
24}
25
26#[derive(Debug, Serialize)]
27#[serde(rename_all = "camelCase")]
28pub struct DownloadableBundles {
29    pub claude_code: String,
30    pub codex: String,
31}
32
33#[derive(Debug, Serialize)]
34#[serde(rename_all = "camelCase")]
35pub struct SkillCapabilities {
36    pub multi_site: bool,
37    pub collections: bool,
38    pub custom_schema: bool,
39    pub typed_tables: bool,
40    pub contracts: bool,
41    pub import_export: bool,
42    pub default_pages: bool,
43    pub media_storage: bool,
44    pub metered_reads: bool,
45}
46
47#[derive(Debug, Serialize)]
48#[serde(rename_all = "camelCase")]
49pub struct SkillReference {
50    pub id: String,
51    pub name: String,
52    pub path: String,
53    pub description: String,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub requires_auth: Option<bool>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub requires_admin: Option<bool>,
58}
59
60#[derive(Debug, Serialize)]
61#[serde(rename_all = "camelCase")]
62pub struct SkillAuth {
63    pub methods: Vec<String>,
64    pub recommended: String,
65    pub header: String,
66}
67
68#[derive(Debug, Serialize)]
69#[serde(rename_all = "camelCase")]
70pub struct RateLimits {
71    pub api_endpoints: String,
72    pub admin_endpoints: String,
73}
74
75// ============================================================================
76// OpenAI Plugin Manifest
77// ============================================================================
78
79#[derive(Debug, Serialize)]
80pub struct AiPluginManifest {
81    pub schema_version: String,
82    pub name_for_human: String,
83    pub name_for_model: String,
84    pub description_for_human: String,
85    pub description_for_model: String,
86    pub auth: AiPluginAuth,
87    pub api: AiPluginApi,
88}
89
90#[derive(Debug, Serialize)]
91pub struct AiPluginAuth {
92    #[serde(rename = "type")]
93    pub auth_type: String,
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub instructions: Option<String>,
96}
97
98#[derive(Debug, Serialize)]
99pub struct AiPluginApi {
100    #[serde(rename = "type")]
101    pub api_type: String,
102    pub url: String,
103}
104
105// ============================================================================
106// Google A2A Agent Card
107// ============================================================================
108
109#[derive(Debug, Serialize)]
110#[serde(rename_all = "camelCase")]
111pub struct AgentCard {
112    pub name: String,
113    pub description: String,
114    pub url: String,
115    pub version: String,
116    pub capabilities: AgentCapabilities,
117    pub authentication: AgentAuthentication,
118    pub skills: Vec<AgentSkill>,
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub documentation_url: Option<String>,
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub provider: Option<AgentProvider>,
123}
124
125#[derive(Debug, Serialize)]
126#[serde(rename_all = "camelCase")]
127pub struct AgentCapabilities {
128    pub streaming: bool,
129    pub push_notifications: bool,
130    pub state_management: bool,
131}
132
133#[derive(Debug, Serialize)]
134#[serde(rename_all = "camelCase")]
135pub struct AgentAuthentication {
136    pub schemes: Vec<AuthScheme>,
137}
138
139#[derive(Debug, Serialize)]
140#[serde(rename_all = "camelCase")]
141pub struct AuthScheme {
142    pub scheme: String,
143    pub description: String,
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub instructions_url: Option<String>,
146}
147
148#[derive(Debug, Serialize)]
149#[serde(rename_all = "camelCase")]
150pub struct AgentSkill {
151    pub id: String,
152    pub name: String,
153    pub description: String,
154    pub input_modes: Vec<String>,
155    pub output_modes: Vec<String>,
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub documentation_url: Option<String>,
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub openapi_tag: Option<String>,
160}
161
162#[derive(Debug, Serialize)]
163#[serde(rename_all = "camelCase")]
164pub struct AgentProvider {
165    pub name: String,
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub url: Option<String>,
168}
169
170// ============================================================================
171// MCP Discovery
172// ============================================================================
173
174#[derive(Debug, Serialize)]
175#[serde(rename_all = "camelCase")]
176pub struct McpDiscovery {
177    pub name: String,
178    pub version: String,
179    pub protocol_version: String,
180    pub description: String,
181    pub capabilities: McpCapabilities,
182    pub tools: Vec<McpTool>,
183    pub authentication: McpAuth,
184}
185
186#[derive(Debug, Serialize)]
187#[serde(rename_all = "camelCase")]
188pub struct McpCapabilities {
189    pub tools: bool,
190    pub resources: bool,
191    pub prompts: bool,
192    pub sampling: bool,
193}
194
195#[derive(Debug, Serialize)]
196#[serde(rename_all = "camelCase")]
197pub struct McpTool {
198    pub name: String,
199    pub description: String,
200    pub input_schema: serde_json::Value,
201}
202
203#[derive(Debug, Serialize)]
204#[serde(rename_all = "camelCase")]
205pub struct McpAuth {
206    pub required: bool,
207    pub schemes: Vec<String>,
208    pub instructions: String,
209}
210
211// ============================================================================
212// AI Discovery Index
213// ============================================================================
214
215#[derive(Debug, Serialize)]
216#[serde(rename_all = "camelCase")]
217pub struct AiDiscoveryIndex {
218    pub version: String,
219    pub name: String,
220    pub description: String,
221    pub endpoints: DiscoveryEndpoints,
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub skills: Option<Vec<SkillPointer>>,
224}
225
226#[derive(Debug, Serialize)]
227#[serde(rename_all = "camelCase")]
228pub struct DiscoveryEndpoints {
229    pub llms_txt: String,
230    pub llms_full_txt: String,
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub llms_admin_txt: Option<String>,
233    pub skill_index_markdown: String,
234    pub skill_index_json: String,
235    pub agent_guide: String,
236    pub openapi: String,
237    pub a2a_agent_card: String,
238    pub ai_plugin: String,
239    pub mcp: String,
240    pub health: String,
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub skills_bundle: Option<String>,
243}
244
245#[derive(Debug, Serialize)]
246#[serde(rename_all = "camelCase")]
247pub struct SkillPointer {
248    pub id: String,
249    pub name: String,
250    pub path: String,
251}
252
253// ============================================================================
254// Heartbeat
255// ============================================================================
256
257#[derive(Debug, Serialize)]
258#[serde(rename_all = "camelCase")]
259pub struct HeartbeatResponse {
260    pub status: String,
261    pub version: String,
262    pub timestamp: String,
263    pub services: ServiceStatus,
264}
265
266#[derive(Debug, Serialize)]
267#[serde(rename_all = "camelCase")]
268pub struct ServiceStatus {
269    pub database: bool,
270    pub storage: bool,
271}