Skip to main content

codex_runtime/runtime/
approvals.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::runtime::rpc_contract::methods;
5
6#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
7#[serde(rename_all = "camelCase")]
8pub struct ServerRequest {
9    pub approval_id: String,
10    pub method: String,
11    pub params: Value,
12}
13
14#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
15#[serde(rename_all = "camelCase")]
16pub struct PendingServerRequest {
17    pub approval_id: String,
18    pub deadline_unix_ms: i64,
19    pub method: String,
20    pub params: Value,
21}
22
23#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
24#[serde(rename_all = "camelCase")]
25pub enum TimeoutAction {
26    Decline,
27    Cancel,
28    Error,
29}
30
31#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
32#[serde(rename_all = "camelCase")]
33pub struct ServerRequestConfig {
34    pub default_timeout_ms: u64,
35    pub on_timeout: TimeoutAction,
36    pub auto_decline_unknown: bool,
37}
38
39#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
40#[serde(rename_all = "camelCase")]
41pub enum ServerRequestRoute {
42    Queue,
43    AutoDecline,
44}
45
46impl Default for ServerRequestConfig {
47    fn default() -> Self {
48        Self {
49            default_timeout_ms: 30_000,
50            on_timeout: TimeoutAction::Decline,
51            auto_decline_unknown: true,
52        }
53    }
54}
55
56/// Pure classifier for known server-request methods.
57/// Allocation: none. Complexity: O(1).
58pub fn is_known_server_request_method(method: &str) -> bool {
59    matches!(
60        method,
61        methods::ITEM_COMMAND_EXECUTION_REQUEST_APPROVAL
62            | methods::ITEM_FILE_CHANGE_REQUEST_APPROVAL
63            | methods::ITEM_TOOL_REQUEST_USER_INPUT
64            | methods::ITEM_TOOL_CALL
65            | methods::ACCOUNT_CHATGPT_AUTH_TOKENS_REFRESH
66    )
67}
68
69/// Decide whether a server request should be queued or auto-declined.
70/// Allocation: none. Complexity: O(1).
71pub fn route_server_request(method: &str, auto_decline_unknown: bool) -> ServerRequestRoute {
72    if auto_decline_unknown && !is_known_server_request_method(method) {
73        ServerRequestRoute::AutoDecline
74    } else {
75        ServerRequestRoute::Queue
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn routes_known_method_to_queue() {
85        let route = route_server_request("item/fileChange/requestApproval", true);
86        assert_eq!(route, ServerRequestRoute::Queue);
87    }
88
89    #[test]
90    fn routes_known_dynamic_tool_call_method_to_queue() {
91        let route = route_server_request("item/tool/call", true);
92        assert_eq!(route, ServerRequestRoute::Queue);
93    }
94
95    #[test]
96    fn routes_known_auth_refresh_method_to_queue() {
97        let route = route_server_request("account/chatgptAuthTokens/refresh", true);
98        assert_eq!(route, ServerRequestRoute::Queue);
99    }
100
101    #[test]
102    fn routes_unknown_method_to_auto_decline_when_enabled() {
103        let route = route_server_request("item/unknown/requestApproval", true);
104        assert_eq!(route, ServerRequestRoute::AutoDecline);
105    }
106
107    #[test]
108    fn routes_unknown_method_to_queue_when_auto_decline_disabled() {
109        let route = route_server_request("item/unknown/requestApproval", false);
110        assert_eq!(route, ServerRequestRoute::Queue);
111    }
112}