Skip to main content

arcan_core/
protocol_bridge.rs

1//! Bridge between Arcan's internal types and the canonical `aios-protocol` types.
2//!
3//! Provides conversions so Arcan can emit canonical events to Lago
4//! and consume canonical types from the protocol without changing its
5//! internal representation.
6
7use crate::protocol::{AgentEvent, ToolCall, ToolResultSummary};
8
9/// Re-export the canonical protocol for downstream convenience.
10pub use aios_protocol;
11
12/// Convert an Arcan `AgentEvent` to a canonical `aios_protocol::EventKind`.
13///
14/// Uses JSON round-trip for simplicity. Variant names that don't match
15/// exactly will fall through to `Custom` on the protocol side.
16pub fn to_protocol_event_kind(event: &AgentEvent) -> Option<aios_protocol::EventKind> {
17    let json = serde_json::to_value(event).ok()?;
18    serde_json::from_value(json).ok()
19}
20
21/// Convert an Arcan `ToolCall` to a canonical `aios_protocol::tool::ToolCall`.
22impl From<&ToolCall> for aios_protocol::tool::ToolCall {
23    fn from(call: &ToolCall) -> Self {
24        aios_protocol::tool::ToolCall {
25            call_id: call.call_id.clone(),
26            tool_name: call.tool_name.clone(),
27            input: call.input.clone(),
28            requested_capabilities: Vec::new(),
29        }
30    }
31}
32
33/// Convert an Arcan `ToolResultSummary` to a protocol-compatible JSON value.
34impl ToolResultSummary {
35    pub fn to_protocol_json(&self) -> serde_json::Value {
36        serde_json::json!({
37            "call_id": self.call_id,
38            "tool_name": self.tool_name,
39            "output": self.output,
40        })
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47    use crate::protocol::AgentEvent;
48
49    #[test]
50    fn agent_event_to_protocol_run_started() {
51        let event = AgentEvent::RunStarted {
52            run_id: "run-1".into(),
53            session_id: "sess-1".into(),
54            provider: "anthropic".into(),
55            max_iterations: 10,
56        };
57        let kind = to_protocol_event_kind(&event);
58        // AgentEvent uses "part_type" tag while protocol uses "type" tag,
59        // so JSON round-trip won't match directly. The event falls to Custom.
60        // This is expected — full alignment happens when Arcan adopts protocol types directly.
61        assert!(kind.is_some());
62    }
63
64    #[test]
65    fn tool_call_conversion() {
66        let arcan_call = ToolCall {
67            call_id: "c1".into(),
68            tool_name: "read_file".into(),
69            input: serde_json::json!({"path": "/tmp"}),
70        };
71        let proto_call: aios_protocol::tool::ToolCall = (&arcan_call).into();
72        assert_eq!(proto_call.call_id, "c1");
73        assert_eq!(proto_call.tool_name, "read_file");
74    }
75}