Download codex-rs/app-server/src/dynamic_tools.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 3.86 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server/src/dynamic_tools.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/app-server/src/dynamic_tools.rs
-
curl -L -o dynamic_tools.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/app-server/src/dynamic_tools.rs
3.86 kB
| use codex_app_server_protocol::DynamicToolCallOutputContentItem; | |
| use codex_app_server_protocol::DynamicToolCallResponse; | |
| use codex_core::CodexThread; | |
| use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem as CoreDynamicToolCallOutputContentItem; | |
| use codex_protocol::dynamic_tools::DynamicToolResponse as CoreDynamicToolResponse; | |
| use codex_protocol::protocol::Op; | |
| use std::sync::Arc; | |
| use tokio::sync::oneshot; | |
| use tracing::error; | |
| use crate::image_url::REMOTE_IMAGE_URL_ERROR; | |
| use crate::image_url::is_remote_image_url; | |
| use crate::outgoing_message::ClientRequestResult; | |
| use crate::server_request_error::is_turn_transition_server_request_error; | |
| const INVALID_AUDIO_URL_ERROR: &str = "audio URLs must use an inline data URL"; | |
| pub(crate) async fn on_call_response( | |
| call_id: String, | |
| receiver: oneshot::Receiver<ClientRequestResult>, | |
| conversation: Arc<CodexThread>, | |
| ) { | |
| let response = receiver.await; | |
| let (response, _error) = match response { | |
| Ok(Ok(value)) => decode_response(value), | |
| Ok(Err(err)) if is_turn_transition_server_request_error(&err) => return, | |
| Ok(Err(err)) => { | |
| error!("request failed with client error: {err:?}"); | |
| fallback_response("dynamic tool request failed") | |
| } | |
| Err(err) => { | |
| error!("request failed: {err:?}"); | |
| fallback_response("dynamic tool request failed") | |
| } | |
| }; | |
| let DynamicToolCallResponse { | |
| content_items, | |
| success, | |
| } = response.clone(); | |
| let core_response = CoreDynamicToolResponse { | |
| content_items: content_items | |
| .into_iter() | |
| .map(CoreDynamicToolCallOutputContentItem::from) | |
| .collect(), | |
| success, | |
| }; | |
| if let Err(err) = conversation | |
| .submit(Op::DynamicToolResponse { | |
| id: call_id.clone(), | |
| response: core_response, | |
| }) | |
| .await | |
| { | |
| error!("failed to submit DynamicToolResponse: {err}"); | |
| } | |
| } | |
| fn decode_response(value: serde_json::Value) -> (DynamicToolCallResponse, Option<String>) { | |
| match serde_json::from_value::<DynamicToolCallResponse>(value) { | |
| Ok(response) | |
| if response.content_items.iter().any(|item| { | |
| matches!( | |
| item, | |
| DynamicToolCallOutputContentItem::InputImage { image_url } | |
| if is_remote_image_url(image_url) | |
| ) | |
| }) => | |
| { | |
| error!( | |
| message = REMOTE_IMAGE_URL_ERROR, | |
| "dynamic tool response was invalid" | |
| ); | |
| fallback_response(REMOTE_IMAGE_URL_ERROR) | |
| } | |
| Ok(response) | |
| if response.content_items.iter().any(|item| { | |
| matches!( | |
| item, | |
| DynamicToolCallOutputContentItem::InputAudio { audio_url } | |
| if !audio_url | |
| .get(.."data:".len()) | |
| .is_some_and(|prefix| prefix.eq_ignore_ascii_case("data:")) | |
| ) | |
| }) => | |
| { | |
| error!( | |
| message = INVALID_AUDIO_URL_ERROR, | |
| "dynamic tool response was invalid" | |
| ); | |
| fallback_response(INVALID_AUDIO_URL_ERROR) | |
| } | |
| Ok(response) => (response, None), | |
| Err(err) => { | |
| error!("failed to deserialize DynamicToolCallResponse: {err}"); | |
| fallback_response("dynamic tool response was invalid") | |
| } | |
| } | |
| } | |
| fn fallback_response(message: &str) -> (DynamicToolCallResponse, Option<String>) { | |
| ( | |
| DynamicToolCallResponse { | |
| content_items: vec![DynamicToolCallOutputContentItem::InputText { | |
| text: message.to_string(), | |
| }], | |
| success: false, | |
| }, | |
| Some(message.to_string()), | |
| ) | |
| } | |