tirea_agentos_server/protocol/ai_sdk_v6/
runtime.rs

1//! Runtime wiring for AI SDK requests.
2//!
3//! Applies AI SDK-specific extensions to a [`ResolvedRun`], currently
4//! no additional plugins.
5
6use std::sync::Arc;
7use tirea_agentos::runtime::loop_runner::ParallelToolExecutor;
8use tirea_agentos::runtime::ResolvedRun;
9
10use tirea_protocol_ai_sdk_v6::AiSdkV6RunRequest;
11
12/// Apply AI SDK-specific extensions to a [`ResolvedRun`].
13pub fn apply_ai_sdk_extensions(resolved: &mut ResolvedRun, _request: &AiSdkV6RunRequest) {
14    // AI SDK transport supports batched approvals; replay only after the full
15    // suspended set receives decisions to avoid partial duplicate replays.
16    resolved.agent.tool_executor = Arc::new(ParallelToolExecutor::batch_approval());
17}
18
19#[cfg(test)]
20mod tests {
21    use super::*;
22    use serde_json::json;
23    use std::collections::HashMap;
24    use tirea_agentos::runtime::loop_runner::BaseAgent;
25    use tirea_contract::RunPolicy;
26
27    fn empty_resolved() -> ResolvedRun {
28        ResolvedRun {
29            agent: BaseAgent::default(),
30            tools: HashMap::new(),
31            run_policy: RunPolicy::new(),
32            parent_tool_call_id: None,
33        }
34    }
35
36    #[test]
37    fn apply_extensions_is_noop_without_decisions() {
38        let req: AiSdkV6RunRequest = serde_json::from_value(json!({
39            "id": "t1",
40            "messages": [{ "role": "user", "content": "hello" }]
41        }))
42        .expect("request should deserialize");
43        let mut resolved = empty_resolved();
44        apply_ai_sdk_extensions(&mut resolved, &req);
45        assert_eq!(
46            resolved.agent.tool_executor.name(),
47            "parallel_batch_approval"
48        );
49    }
50
51    #[test]
52    fn apply_extensions_is_noop_with_decisions() {
53        let req: AiSdkV6RunRequest = serde_json::from_value(json!({
54            "id": "t2",
55            "messages": [{
56                "role": "assistant",
57                "parts": [{
58                    "type": "tool-approval-response",
59                    "approvalId": "fc_1",
60                    "approved": true
61                }]
62            }]
63        }))
64        .expect("request should deserialize");
65        let mut resolved = empty_resolved();
66        apply_ai_sdk_extensions(&mut resolved, &req);
67        assert_eq!(
68            resolved.agent.tool_executor.name(),
69            "parallel_batch_approval"
70        );
71    }
72}