Skip to main content

soma_codemode/
openapi_feature.rs

1use crate::ToolError;
2
3#[cfg(feature = "openapi")]
4use serde_json::Value;
5
6#[cfg(feature = "openapi")]
7pub use soma_openapi::OpenApiRegistry;
8
9#[cfg(feature = "openapi")]
10#[must_use]
11pub fn split_openapi_method(method: &str) -> Option<(&str, &str)> {
12    let (label, operation_id) = method.split_once('.')?;
13    if label.is_empty() || operation_id.is_empty() {
14        return None;
15    }
16    Some((label, operation_id))
17}
18
19#[cfg(not(feature = "openapi"))]
20#[must_use]
21pub fn openapi_provider_unavailable_error() -> ToolError {
22    ToolError::UnknownAction {
23        message: "unknown Code Mode local provider `openapi`".to_string(),
24        valid: vec!["state".to_string(), "git".to_string()],
25        hint: None,
26    }
27}
28
29#[cfg(feature = "openapi")]
30pub async fn dispatch_openapi_provider(
31    registry: &soma_openapi::OpenApiRegistry,
32    client: &reqwest::Client,
33    method: &str,
34    params: Value,
35) -> Result<Value, ToolError> {
36    let (label, operation_id) =
37        split_openapi_method(method).ok_or_else(|| ToolError::InvalidParam {
38            message: "openapi call must be openapi::<label>.<operationId>".to_string(),
39            param: "id".to_string(),
40        })?;
41    soma_openapi::dispatch_openapi_call(registry, client, label, operation_id, params)
42        .await
43        .map_err(openapi_error_to_tool_error)
44}
45
46#[cfg(feature = "openapi")]
47#[must_use]
48pub fn openapi_error_to_tool_error(error: soma_openapi::OpenApiError) -> ToolError {
49    match error {
50        soma_openapi::OpenApiError::UnknownInstance { label, valid } => {
51            ToolError::UnknownInstance {
52                message: format!("unknown OpenAPI spec label `{label}`"),
53                valid,
54            }
55        }
56        soma_openapi::OpenApiError::UnknownOperation {
57            label,
58            operation_id,
59        } => ToolError::UnknownAction {
60            message: format!("unknown OpenAPI operation `{operation_id}` in `{label}`"),
61            valid: Vec::new(),
62            hint: None,
63        },
64        soma_openapi::OpenApiError::InvalidPathParam { label, param } => ToolError::InvalidParam {
65            message: format!(
66                "OpenAPI operation `{label}` path parameter `{param}` is missing or invalid"
67            ),
68            param,
69        },
70        soma_openapi::OpenApiError::RequestBlockedPrivateAddr { .. } => ToolError::Forbidden {
71            message: error.to_string(),
72            required_scopes: vec!["openapi".to_string()],
73        },
74        soma_openapi::OpenApiError::UpstreamTimeout { .. } => ToolError::Sdk {
75            sdk_kind: "timeout".to_string(),
76            message: error.to_string(),
77        },
78        other => ToolError::Sdk {
79            sdk_kind: other.kind().to_string(),
80            message: other.to_string(),
81        },
82    }
83}