Skip to main content

ldp_protocol/
protocol.rs

1//! Standalone protocol abstractions for LDP.
2//!
3//! These types define the adapter interface for LDP, allowing it to operate
4//! independently or as a plugin within runtimes like JamJet.
5
6use crate::types::error::LdpError;
7use async_trait::async_trait;
8use futures::Stream;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use std::pin::Pin;
12
13/// A skill exposed by a remote delegate.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct RemoteSkill {
16    /// Skill name (e.g., "reasoning", "summarization").
17    pub name: String,
18    /// Human-readable description.
19    pub description: Option<String>,
20    /// JSON Schema for expected input.
21    pub input_schema: Option<Value>,
22    /// JSON Schema for expected output.
23    pub output_schema: Option<Value>,
24}
25
26/// Capabilities discovered from a remote delegate.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct RemoteCapabilities {
29    /// Delegate display name.
30    pub name: String,
31    /// Human-readable description.
32    pub description: Option<String>,
33    /// Available skills.
34    pub skills: Vec<RemoteSkill>,
35    /// Supported protocols (e.g., `["ldp"]`).
36    pub protocols: Vec<String>,
37}
38
39/// A request to execute a task on a remote delegate.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct TaskRequest {
42    /// The skill to invoke.
43    pub skill: String,
44    /// Input data for the task.
45    pub input: Value,
46}
47
48/// Handle returned after submitting a task.
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct TaskHandle {
51    /// Unique identifier for the submitted task.
52    pub task_id: String,
53    /// URL of the remote delegate handling the task.
54    pub remote_url: String,
55}
56
57/// Events emitted during task streaming.
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub enum TaskEvent {
60    /// Progress update.
61    Progress {
62        message: String,
63        progress: Option<f32>,
64    },
65    /// Task completed successfully.
66    Completed { output: Value },
67    /// Task failed.
68    Failed { error: LdpError },
69}
70
71/// Current status of a submitted task.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub enum TaskStatus {
74    /// Task has been submitted but not yet started.
75    Submitted,
76    /// Task is actively being processed.
77    Working,
78    /// Task completed with output.
79    Completed { output: Value },
80    /// Task failed with an error.
81    Failed { error: LdpError },
82}
83
84/// Async stream of task events.
85pub type TaskStream = Pin<Box<dyn Stream<Item = TaskEvent> + Send>>;
86
87/// Protocol adapter trait — the core abstraction for delegate communication.
88///
89/// Implementations handle the full lifecycle: discovery, invocation, streaming,
90/// status polling, and cancellation.
91#[async_trait]
92pub trait ProtocolAdapter: Send + Sync {
93    /// Discover capabilities of a remote delegate.
94    async fn discover(&self, url: &str) -> Result<RemoteCapabilities, String>;
95
96    /// Submit a task for execution and return a handle.
97    async fn invoke(&self, url: &str, task: TaskRequest) -> Result<TaskHandle, String>;
98
99    /// Submit a task and stream progress events.
100    async fn stream(&self, url: &str, task: TaskRequest) -> Result<TaskStream, String>;
101
102    /// Poll the current status of a submitted task.
103    async fn status(&self, url: &str, task_id: &str) -> Result<TaskStatus, String>;
104
105    /// Cancel a running task.
106    async fn cancel(&self, url: &str, task_id: &str) -> Result<(), String>;
107}
108
109/// Registry for protocol adapters, mapping protocol names to implementations.
110///
111/// Supports URL-based routing: adapters register URL prefixes, and the registry
112/// resolves which adapter handles a given URL.
113pub struct ProtocolRegistry {
114    adapters: Vec<(String, std::sync::Arc<dyn ProtocolAdapter>, Vec<String>)>,
115}
116
117impl ProtocolRegistry {
118    /// Create an empty registry.
119    pub fn new() -> Self {
120        Self {
121            adapters: Vec::new(),
122        }
123    }
124
125    /// Register an adapter with a protocol name and URL prefixes.
126    pub fn register(
127        &mut self,
128        name: &str,
129        adapter: std::sync::Arc<dyn ProtocolAdapter>,
130        url_prefixes: Vec<&str>,
131    ) {
132        self.adapters.push((
133            name.to_string(),
134            adapter,
135            url_prefixes.iter().map(|s| s.to_string()).collect(),
136        ));
137    }
138
139    /// Look up an adapter by protocol name.
140    pub fn adapter(&self, name: &str) -> Option<&dyn ProtocolAdapter> {
141        self.adapters
142            .iter()
143            .find(|(n, _, _)| n == name)
144            .map(|(_, a, _)| a.as_ref())
145    }
146
147    /// Find the adapter that handles a given URL.
148    pub fn adapter_for_url(&self, url: &str) -> Option<&dyn ProtocolAdapter> {
149        self.adapters
150            .iter()
151            .find(|(_, _, prefixes)| prefixes.iter().any(|p| url.starts_with(p)))
152            .map(|(_, a, _)| a.as_ref())
153    }
154
155    /// List all registered protocol names.
156    pub fn protocols(&self) -> Vec<&str> {
157        self.adapters.iter().map(|(n, _, _)| n.as_str()).collect()
158    }
159}
160
161impl Default for ProtocolRegistry {
162    fn default() -> Self {
163        Self::new()
164    }
165}