warmplane 0.30.0

Local control plane that keeps MCP sessions warm with compact capability/resource/prompt facades.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
// Rust guideline compliant 2026-08-20

//! Strongly typed envelopes, capability representations, errors, and batch results for embedded engine execution (`M-CANONICAL-DOCS`).

use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::{context::RequestContext, idempotency::RetryMetadata};

/// Strongly typed response envelope returned by all embedded Warmplane operations.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Envelope<T> {
    /// Whether the execution completed successfully.
    pub ok: bool,
    /// Optional contextual request identifier.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub request_id: Option<String>,
    /// Request context metadata propagation envelope.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub context: Option<RequestContext>,
    /// Monotonically generated trace identifier.
    pub trace_id: String,
    /// Payload data on success (`None` if failed).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub data: Option<T>,
    /// Error details on failure (`None` if successful).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error: Option<WarmplaneError>,
    /// Retry safety classification and execution state.
    pub retry: RetryMetadata,
}

/// Builder for constructing structured `Envelope<T>` responses (`M-INIT-BUILDER`).
pub struct EnvelopeBuilder<T> {
    ok: bool,
    trace_id: String,
    request_id: Option<String>,
    context: Option<RequestContext>,
    data: Option<T>,
    error: Option<WarmplaneError>,
    retry: RetryMetadata,
}

impl<T> EnvelopeBuilder<T> {
    /// Creates a new builder for a given trace ID and retry classification.
    pub fn new(trace_id: impl Into<String>, retry: RetryMetadata) -> Self {
        Self {
            ok: true,
            trace_id: trace_id.into(),
            request_id: None,
            context: None,
            data: None,
            error: None,
            retry,
        }
    }

    /// Attaches an optional request ID.
    pub fn request_id(mut self, request_id: Option<String>) -> Self {
        self.request_id = request_id;
        self
    }

    /// Attaches an optional request context.
    pub fn context(mut self, context: Option<RequestContext>) -> Self {
        self.context = context;
        self
    }

    /// Sets successful execution with given data payload.
    pub fn success(mut self, data: T) -> Self {
        self.ok = true;
        self.data = Some(data);
        self.error = None;
        self
    }

    /// Sets failed execution with error payload.
    pub fn error(mut self, error: WarmplaneError) -> Self {
        self.ok = false;
        self.data = None;
        self.error = Some(error);
        self
    }

    /// Builds the final `Envelope<T>`.
    pub fn build(self) -> Envelope<T> {
        Envelope {
            ok: self.ok,
            request_id: self.request_id,
            context: self.context,
            trace_id: self.trace_id,
            data: self.data,
            error: self.error,
            retry: self.retry,
        }
    }
}

impl<T> Envelope<T> {
    /// Constructs a successful response envelope.
    pub fn success(
        trace_id: String,
        request_id: Option<String>,
        context: Option<RequestContext>,
        data: T,
        retry: RetryMetadata,
    ) -> Self {
        let mut b = EnvelopeBuilder::new(trace_id, retry);
        b.request_id = request_id;
        b.context = context;
        b.success(data).build()
    }

    /// Constructs an error response envelope.
    pub fn failure(
        trace_id: String,
        request_id: Option<String>,
        context: Option<RequestContext>,
        error: WarmplaneError,
        retry: RetryMetadata,
    ) -> Self {
        Self {
            ok: false,
            request_id,
            context,
            trace_id,
            data: None,
            error: Some(error),
            retry,
        }
    }
}

/// Standard error structure included in failed response envelopes.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct WarmplaneError {
    /// Machine-readable error code.
    pub code: String,
    /// Human-readable error description.
    pub message: String,
    /// Whether this error is transient and safe to retry.
    pub retryable: bool,
    /// Optional operator identifier if rejected by human-in-the-loop review.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operator: Option<String>,
}

impl WarmplaneError {
    /// Creates a new `WarmplaneError`.
    pub fn new(code: impl Into<String>, message: impl Into<String>, retryable: bool) -> Self {
        Self {
            code: code.into(),
            message: message.into(),
            retryable,
            operator: None,
        }
    }

    /// Creates a HITL operator rejection error.
    pub fn operator_rejected(operator: impl Into<String>, reason: Option<String>) -> Self {
        let op = operator.into();
        let reason_str = reason.map(|r| format!(": {}", r)).unwrap_or_default();
        Self {
            code: "OPERATION_REJECTED_BY_OPERATOR".to_string(),
            message: format!("Human operator rejected execution{}", reason_str),
            retryable: false,
            operator: Some(op),
        }
    }
}

/// Compact capability metadata summary for catalog indexing and discovery.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilitySummary {
    /// Unique capability identifier or alias.
    pub id: String,
    /// Short summary of tool function.
    pub summary: String,
    /// Upstream MCP server hosting this tool.
    pub server: String,
    /// Underlying tool name on upstream server.
    pub tool: String,
    /// Compact LLM-friendly call signature (e.g. `tool_name(req1, [opt1])`).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub signature: Option<String>,
    /// Discovery tags.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub tags: Vec<String>,
}

/// Detailed capability specification including schema and examples for on-demand inspection.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilityDetail {
    /// Unique capability identifier.
    pub id: String,
    /// Upstream MCP server hosting this tool.
    pub server: String,
    /// Underlying tool name on upstream server.
    pub tool: String,
    /// Comprehensive tool description.
    pub description: String,
    /// JSON Schema definition for arguments.
    pub input_schema: Value,
    /// Usage examples.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub examples: Vec<Value>,
}

/// Response payload for capability catalog listing.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilitiesListResponse {
    /// API schema version (`"v1"`).
    pub version: String,
    /// List of registered capability summaries.
    pub capabilities: Vec<CapabilitySummary>,
    /// Search engine runtime info and feature status.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_engine: Option<crate::search::SearchEngineInfo>,
}

/// Response payload for capability search.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilitySearchResponse {
    /// API schema version (`"v1"`).
    pub version: String,
    /// Active catalog version ETag.
    pub catalog_version: String,
    /// Plaintext query searched.
    pub query: String,
    /// Total number of matching capabilities.
    pub total: usize,
    /// Search results ranked by relevance.
    pub capabilities: Vec<crate::search::hybrid::CapabilitySearchResult>,
}

/// Response payload for capability schema describe.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CapabilityDescribeResponse {
    /// API schema version (`"v1"`).
    pub version: String,
    /// Detailed capability metadata.
    pub capability: CapabilityDetail,
}

/// Compact resource metadata summary.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ResourceSummary {
    /// Resource identifier or alias.
    pub id: String,
    /// Upstream server providing resource.
    pub server: String,
    /// Resource URI.
    pub uri: String,
    /// Human-readable resource name.
    pub name: String,
    /// Optional resource description.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Optional MIME type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mime_type: Option<String>,
    /// Resource tags.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub tags: Vec<String>,
}

/// Response payload for listing resources.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ResourcesListResponse {
    /// API schema version (`"v1"`).
    pub version: String,
    /// List of available resources.
    pub resources: Vec<ResourceSummary>,
}

/// Compact prompt metadata summary.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PromptSummary {
    /// Prompt identifier or alias.
    pub id: String,
    /// Upstream server providing prompt.
    pub server: String,
    /// Prompt name.
    pub name: String,
    /// Optional human-readable title.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    /// Optional description.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Expected prompt template arguments.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub arguments: Vec<Value>,
    /// Prompt tags.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub tags: Vec<String>,
}

/// Response payload for listing prompts.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PromptsListResponse {
    /// API schema version (`"v1"`).
    pub version: String,
    /// List of registered prompts.
    pub prompts: Vec<PromptSummary>,
}

/// Health and status overview of the embedded Warmplane control plane.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EngineHealthStatus {
    /// Current catalog SHA256 version ETag.
    pub catalog_version: String,
    /// Map of connected upstream servers and their statuses.
    pub server_statuses: std::collections::HashMap<String, Value>,
    /// Circuit breaker status for each upstream server.
    pub circuit_breakers: std::collections::HashMap<String, crate::circuit_breaker::CircuitState>,
    /// Total capability tool calls processed.
    pub total_tool_calls: u64,
    /// Total duration in microseconds across all tool executions.
    pub total_tool_duration_us: u64,
}

pub use crate::tasks::{TaskRecord, TaskResponse, TaskStatus};

/// Optional invocation settings for calling a capability tool.
#[derive(Debug, Clone, Default)]
pub struct ExecutionOptions {
    /// Contextual request identifier.
    pub request_id: Option<String>,
    /// Distributed tracing or security context metadata.
    pub context: Option<RequestContext>,
    /// Idempotency deduplication key.
    pub idempotency_key: Option<String>,
    /// Multi-roundtrip client input responses.
    pub input_responses: Option<std::collections::BTreeMap<String, Value>>,
    /// Multi-roundtrip opaque request state.
    pub request_state: Option<String>,
    /// Named server profile restricting visibility.
    pub profile: Option<String>,
    /// Request asynchronous execution as a SEP-2663 task handle.
    pub async_task: bool,
}

impl ExecutionOptions {
    /// Creates default `ExecutionOptions`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Sets request ID.
    pub fn with_request_id(mut self, id: impl Into<String>) -> Self {
        self.request_id = Some(id.into());
        self
    }

    /// Sets profile.
    pub fn with_profile(mut self, profile: impl Into<String>) -> Self {
        self.profile = Some(profile.into());
        self
    }

    /// Sets idempotency key.
    pub fn with_idempotency_key(mut self, key: impl Into<String>) -> Self {
        self.idempotency_key = Some(key.into());
        self
    }

    /// Sets async_task execution mode.
    pub fn with_async_task(mut self, async_task: bool) -> Self {
        self.async_task = async_task;
        self
    }
}

/// Optional parameters for reading a resource.
#[derive(Debug, Clone, Default)]
pub struct ReadResourceOptions {
    /// Contextual request identifier.
    pub request_id: Option<String>,
    /// Distributed tracing or security context metadata.
    pub context: Option<RequestContext>,
    /// Multi-roundtrip client input responses.
    pub input_responses: Option<std::collections::BTreeMap<String, Value>>,
    /// Multi-roundtrip opaque request state.
    pub request_state: Option<String>,
    /// Named server profile restricting visibility.
    pub profile: Option<String>,
}

/// Optional parameters for rendering a prompt template.
#[derive(Debug, Clone, Default)]
pub struct GetPromptOptions {
    /// Contextual request identifier.
    pub request_id: Option<String>,
    /// Distributed tracing or security context metadata.
    pub context: Option<RequestContext>,
    /// Template interpolation arguments.
    pub arguments: Option<Value>,
    /// Multi-roundtrip client input responses.
    pub input_responses: Option<std::collections::BTreeMap<String, Value>>,
    /// Multi-roundtrip opaque request state.
    pub request_state: Option<String>,
    /// Named server profile restricting visibility.
    pub profile: Option<String>,
}