Skip to main content

chio_cross_protocol/
semantic_hints.rs

1use chio_manifest::{LatencyHint, ToolDefinition};
2use serde::{Deserialize, Serialize};
3
4use crate::validation::schema_bool_extension;
5
6/// Truthful bridge fidelity contract for publication gating.
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case", tag = "kind")]
9pub enum BridgeFidelity {
10    Lossless,
11    Adapted { caveats: Vec<String> },
12    Unsupported { reason: String },
13}
14
15impl BridgeFidelity {
16    #[must_use]
17    pub fn published_by_default(&self) -> bool {
18        !matches!(self, Self::Unsupported { .. })
19    }
20
21    #[must_use]
22    pub fn caveats(&self) -> &[String] {
23        match self {
24            Self::Adapted { caveats } => caveats.as_slice(),
25            Self::Lossless | Self::Unsupported { .. } => &[],
26        }
27    }
28
29    #[must_use]
30    pub fn unsupported_reason(&self) -> Option<&str> {
31        match self {
32            Self::Unsupported { reason } => Some(reason.as_str()),
33            Self::Lossless | Self::Adapted { .. } => None,
34        }
35    }
36}
37
38/// Semantic hints that influence truthful bridge publication decisions.
39#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "camelCase")]
41pub struct BridgeSemanticHints {
42    pub publish: bool,
43    pub approval_required: bool,
44    pub streams_output: bool,
45    pub supports_cancellation: bool,
46    pub partial_output: bool,
47}
48
49/// Extract bridge-semantic hints from a tool definition and optional `x-chio-*`
50/// schema extensions.
51#[must_use]
52pub fn semantic_hints_for_tool(tool: &ToolDefinition) -> BridgeSemanticHints {
53    let publish = schema_bool_extension(&tool.input_schema, "x-chio-publish")
54        .or_else(|| {
55            tool.output_schema
56                .as_ref()
57                .and_then(|schema| schema_bool_extension(schema, "x-chio-publish"))
58        })
59        .unwrap_or(true);
60
61    let approval_required = schema_bool_extension(&tool.input_schema, "x-chio-approval-required")
62        .or_else(|| {
63            tool.output_schema
64                .as_ref()
65                .and_then(|schema| schema_bool_extension(schema, "x-chio-approval-required"))
66        })
67        .unwrap_or(false);
68
69    let streams_output = schema_bool_extension(&tool.input_schema, "x-chio-streaming")
70        .or_else(|| {
71            tool.output_schema
72                .as_ref()
73                .and_then(|schema| schema_bool_extension(schema, "x-chio-streaming"))
74        })
75        .unwrap_or(matches!(
76            tool.latency_hint,
77            Some(LatencyHint::Moderate | LatencyHint::Slow)
78        ));
79
80    let supports_cancellation = schema_bool_extension(&tool.input_schema, "x-chio-cancellation")
81        .or_else(|| {
82            tool.output_schema
83                .as_ref()
84                .and_then(|schema| schema_bool_extension(schema, "x-chio-cancellation"))
85        })
86        .unwrap_or(matches!(tool.latency_hint, Some(LatencyHint::Slow)));
87
88    let partial_output = schema_bool_extension(&tool.input_schema, "x-chio-partial-output")
89        .or_else(|| {
90            tool.output_schema
91                .as_ref()
92                .and_then(|schema| schema_bool_extension(schema, "x-chio-partial-output"))
93        })
94        .unwrap_or(streams_output);
95
96    BridgeSemanticHints {
97        publish,
98        approval_required,
99        streams_output,
100        supports_cancellation,
101        partial_output,
102    }
103}