1use serde::{Deserialize, Serialize};
14use std::collections::HashMap;
15use std::sync::Arc;
16
17pub use crate::types::hooks::HookProgress;
21pub use crate::types::message::{
22 AssistantMessage, AttachmentMessage, Message, ProgressMessage, SystemLocalCommandMessage,
23 SystemMessage, UserMessage,
24};
25pub use crate::types::tools::ToolProgressData;
26pub use crate::types::{ToolDefinition, ToolInputSchema};
27
28pub type ToolInputJsonSchema = serde_json::Value;
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct QueryChainTracking {
42 #[serde(rename = "chainId")]
43 pub chain_id: String,
44 pub depth: u32,
45}
46
47#[derive(Debug, Clone)]
53pub enum ValidationResult {
54 Valid,
56 Invalid { message: String, error_code: i64 },
58}
59
60pub type SetToolJsxFn = Arc<
67 dyn Fn(Option<SetToolJsxArgs>) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send + 'static>>
68 + Send
69 + Sync,
70>;
71
72#[derive(Debug, Clone)]
73pub struct SetToolJsxArgs {
74 pub should_hide_prompt_input: bool,
75 pub should_continue_animation: bool,
76 pub show_spinner: bool,
77 pub is_local_jsx: bool,
78 pub is_immediate: bool,
79 pub clear_local_jsx: bool,
81}
82
83pub use crate::types::CompactProgressEvent;
88
89pub use crate::types::permissions::ToolPermissionContext;
94
95pub fn get_empty_tool_permission_context() -> ToolPermissionContext {
97 ToolPermissionContext {
98 mode: "default".to_string(),
99 additional_working_directories: HashMap::new(),
100 always_allow_rules: crate::types::permissions::ToolPermissionRulesBySource {
101 user_settings: None,
102 project_settings: None,
103 local_settings: None,
104 flag_settings: None,
105 policy_settings: None,
106 cli_arg: None,
107 command: None,
108 session: None,
109 },
110 always_deny_rules: crate::types::permissions::ToolPermissionRulesBySource {
111 user_settings: None,
112 project_settings: None,
113 local_settings: None,
114 flag_settings: None,
115 policy_settings: None,
116 cli_arg: None,
117 command: None,
118 session: None,
119 },
120 always_ask_rules: crate::types::permissions::ToolPermissionRulesBySource {
121 user_settings: None,
122 project_settings: None,
123 local_settings: None,
124 flag_settings: None,
125 policy_settings: None,
126 cli_arg: None,
127 command: None,
128 session: None,
129 },
130 is_bypass_permissions_mode_available: false,
131 stripped_dangerous_rules: None,
132 should_avoid_permission_prompts: None,
133 await_automated_checks_before_dialog: None,
134 pre_plan_mode: None,
135 }
136}
137
138pub struct ToolUseContext {
147 pub options: ToolUseContextOptions,
148 pub abort_signal: Option<()>,
150 pub read_file_state: Option<Arc<dyn std::any::Any + Send + Sync>>,
151 pub get_app_state: Box<dyn Fn() -> Box<dyn std::any::Any> + Send + Sync>,
152 pub set_app_state:
153 Box<dyn Fn(Box<dyn Fn(Box<dyn std::any::Any>) -> Box<dyn std::any::Any>>) + Send + Sync>,
154 pub set_app_state_for_tasks: Option<
155 Box<dyn Fn(Box<dyn Fn(Box<dyn std::any::Any>) -> Box<dyn std::any::Any>>) + Send + Sync>,
156 >,
157 pub handle_elicitation: Option<
158 Arc<
159 dyn Fn(
160 String,
161 serde_json::Value,
162 (),
163 )
164 -> std::pin::Pin<Box<dyn Future<Output = serde_json::Value> + Send>>
165 + Send
166 + Sync,
167 >,
168 >,
169 pub set_tool_jsx: Option<SetToolJsxFn>,
170 pub add_notification: Option<Arc<dyn Fn(serde_json::Value) + Send + Sync>>,
171 pub append_system_message: Option<Box<dyn Fn(SystemMessage) + Send + Sync>>,
172 pub send_os_notification: Option<Box<dyn Fn(String, String) + Send + Sync>>,
173 pub nested_memory_attachment_triggers:
174 Option<Arc<std::sync::Mutex<std::collections::HashSet<String>>>>,
175 pub loaded_nested_memory_paths:
176 Option<Arc<std::sync::Mutex<std::collections::HashSet<String>>>>,
177 pub dynamic_skill_dir_triggers:
178 Option<Arc<std::sync::Mutex<std::collections::HashSet<String>>>>,
179 pub discovered_skill_names: Option<Arc<std::sync::Mutex<std::collections::HashSet<String>>>>,
180 pub user_modified: bool,
181 pub set_in_progress_tool_use_ids: Box<
182 dyn Fn(Box<dyn Fn(&std::collections::HashSet<String>) -> std::collections::HashSet<String>>)
183 + Send
184 + Sync,
185 >,
186 pub set_has_interruptible_tool_in_progress: Option<Box<dyn Fn(bool) + Send + Sync>>,
187 pub set_response_length: Box<dyn Fn(Box<dyn Fn(usize) -> usize>) + Send + Sync>,
188 pub push_api_metrics_entry: Option<Box<dyn Fn(u64) + Send + Sync>>,
189 pub set_stream_mode: Option<Box<dyn Fn(String) + Send + Sync>>,
190 pub on_compact_progress: Option<Box<dyn Fn(CompactProgressEvent) + Send + Sync>>,
191 pub set_sdk_status: Option<Box<dyn Fn(String) + Send + Sync>>,
192 pub open_message_selector: Option<Box<dyn Fn() + Send + Sync>>,
193 pub update_file_history_state:
194 Box<dyn Fn(Box<dyn Fn(Box<dyn std::any::Any>) -> Box<dyn std::any::Any>>) + Send + Sync>,
195 pub update_attribution_state:
196 Box<dyn Fn(Box<dyn Fn(Box<dyn std::any::Any>) -> Box<dyn std::any::Any>>) + Send + Sync>,
197 pub set_conversation_id: Option<Box<dyn Fn(String) + Send + Sync>>,
198 pub agent_id: Option<String>,
199 pub agent_type: Option<String>,
200 pub require_can_use_tool: bool,
201 pub messages: Vec<Message>,
202 pub file_reading_limits: Option<FileReadingLimits>,
203 pub glob_limits: Option<GlobLimits>,
204 pub tool_decisions: Option<Arc<std::sync::Mutex<HashMap<String, ToolDecisionEntry>>>>,
205 pub query_tracking: Option<QueryChainTracking>,
206 pub request_prompt: Option<
207 Arc<
208 dyn Fn(
209 String,
210 Option<String>,
211 ) -> Box<
212 dyn Fn(
213 serde_json::Value,
214 )
215 -> std::pin::Pin<Box<dyn Future<Output = serde_json::Value> + Send>>
216 + Send,
217 > + Send
218 + Sync,
219 >,
220 >,
221 pub tool_use_id: Option<String>,
222 pub critical_system_reminder_experimental: Option<String>,
223 pub preserve_tool_use_results: bool,
224 pub local_denial_tracking: Option<Arc<std::sync::Mutex<DenialTrackingState>>>,
225 pub content_replacement_state: Option<Arc<dyn std::any::Any + Send + Sync>>,
226 pub rendered_system_prompt: Option<Arc<dyn std::any::Any + Send + Sync>>,
227}
228
229impl ToolUseContext {
230 pub fn stub() -> Self {
233 use std::collections::HashSet;
234 use crate::types::message::Message;
235 Self {
236 options: ToolUseContextOptions {
237 commands: Vec::new(),
238 debug: false,
239 main_loop_model: String::new(),
240 tools: Vec::new(),
241 verbose: false,
242 thinking_config: None,
243 mcp_clients: Vec::new(),
244 mcp_resources: HashMap::new(),
245 is_non_interactive_session: false,
246 agent_definitions: AgentDefinitionsResult {
247 active_agents: Vec::new(),
248 all_agents: Vec::new(),
249 },
250 max_budget_usd: None,
251 custom_system_prompt: None,
252 append_system_prompt: None,
253 query_source: None,
254 refresh_tools: None,
255 },
256 abort_signal: None,
257 read_file_state: None,
258 get_app_state: Box::new(|| Box::new(()) as Box<dyn std::any::Any>),
259 set_app_state: Box::new(|_| {}),
260 set_app_state_for_tasks: None,
261 handle_elicitation: None,
262 set_tool_jsx: None,
263 add_notification: None,
264 append_system_message: None,
265 send_os_notification: None,
266 nested_memory_attachment_triggers: None,
267 loaded_nested_memory_paths: None,
268 dynamic_skill_dir_triggers: None,
269 discovered_skill_names: None,
270 user_modified: false,
271 set_in_progress_tool_use_ids: Box::new(|_| ()),
272 set_has_interruptible_tool_in_progress: None,
273 set_response_length: Box::new(|_| {}),
274 push_api_metrics_entry: None,
275 set_stream_mode: None,
276 on_compact_progress: None,
277 set_sdk_status: None,
278 open_message_selector: None,
279 update_file_history_state: Box::new(|_| ()),
280 update_attribution_state: Box::new(|_| ()),
281 set_conversation_id: None,
282 agent_id: None,
283 agent_type: None,
284 require_can_use_tool: false,
285 messages: Vec::<Message>::new(),
286 file_reading_limits: None,
287 glob_limits: None,
288 tool_decisions: None,
289 query_tracking: None,
290 request_prompt: None,
291 tool_use_id: None,
292 critical_system_reminder_experimental: None,
293 preserve_tool_use_results: false,
294 local_denial_tracking: None,
295 content_replacement_state: None,
296 rendered_system_prompt: None,
297 }
298 }
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub struct FileReadingLimits {
303 #[serde(skip_serializing_if = "Option::is_none")]
304 pub max_tokens: Option<u64>,
305 #[serde(rename = "maxSizeBytes", skip_serializing_if = "Option::is_none")]
306 pub max_size_bytes: Option<u64>,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct GlobLimits {
311 #[serde(rename = "maxResults", skip_serializing_if = "Option::is_none")]
312 pub max_results: Option<u64>,
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
316pub struct ToolDecisionEntry {
317 pub source: String,
318 pub decision: String, pub timestamp: u64,
320}
321
322#[derive(Debug, Clone, Default, Serialize, Deserialize)]
323pub struct DenialTrackingState {
324 pub count: u32,
325}
326
327#[derive(Clone)]
328pub struct ToolUseContextOptions {
329 pub commands: Vec<serde_json::Value>,
330 pub debug: bool,
331 pub main_loop_model: String,
332 pub tools: Vec<ToolDefinition>,
333 pub verbose: bool,
334 pub thinking_config: Option<serde_json::Value>,
335 pub mcp_clients: Vec<serde_json::Value>,
336 pub mcp_resources: HashMap<String, Vec<serde_json::Value>>,
337 pub is_non_interactive_session: bool,
338 pub agent_definitions: AgentDefinitionsResult,
339 pub max_budget_usd: Option<f64>,
340 pub custom_system_prompt: Option<String>,
341 pub append_system_prompt: Option<String>,
342 pub query_source: Option<String>,
343 #[allow(clippy::type_complexity)]
344 pub refresh_tools: Option<Arc<dyn Fn() -> Vec<ToolDefinition> + Send + Sync>>,
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
348pub struct AgentDefinitionsResult {
349 #[serde(rename = "activeAgents")]
350 pub active_agents: Vec<serde_json::Value>,
351 #[serde(rename = "allAgents")]
352 pub all_agents: Vec<serde_json::Value>,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
361pub struct ToolProgress<P = ToolProgressData> {
362 #[serde(rename = "toolUseID")]
363 pub tool_use_id: String,
364 pub data: P,
365}
366
367pub fn filter_tool_progress_messages(
371 progress_messages: &[ProgressMessage],
372) -> Vec<ProgressMessage> {
373 progress_messages
374 .iter()
375 .filter(|msg| {
376 msg.progress
377 .as_ref()
378 .and_then(|d| d.get("kind"))
379 .and_then(|k| k.as_str())
380 != Some("hook_progress")
381 })
382 .cloned()
383 .collect()
384}
385
386pub struct ToolResult<T = serde_json::Value> {
394 pub data: T,
395 pub new_messages: Option<Vec<ToolResultMessage>>,
396 pub context_modifier: Option<Arc<dyn Fn(&ToolUseContext) -> ToolUseContext + Send + Sync>>,
398 pub mcp_meta: Option<McpMeta>,
400}
401
402pub enum ToolResultMessage {
404 User(UserMessage),
405 Assistant(AssistantMessage),
406 Attachment(AttachmentMessage),
407 System(SystemMessage),
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct McpMeta {
413 #[serde(skip_serializing_if = "Option::is_none")]
414 pub meta: Option<HashMap<String, serde_json::Value>>,
415 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
416 pub structured_content: Option<HashMap<String, serde_json::Value>>,
417}
418
419pub type ToolCallProgressFn<P = ToolProgressData> = Arc<
425 dyn Fn(ToolProgress<P>) -> std::pin::Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync,
426>;
427
428pub fn tool_matches_name(name: &str, aliases: Option<&[String]>, target: &str) -> bool {
436 name == target || aliases.is_some_and(|a| a.iter().any(|alias| alias == target))
437}
438
439pub fn find_tool_by_name<'a>(
443 tools: &'a [ToolDefinition],
444 name: &str,
445) -> Option<&'a ToolDefinition> {
446 tools
447 .iter()
448 .find(|t| tool_matches_name(&t.name, None, name))
449}
450
451#[derive(Debug, Clone, Serialize, Deserialize)]
457pub struct ToolResultBlockParam {
458 #[serde(rename = "type")]
459 pub block_type: String,
460 #[serde(rename = "tool_use_id")]
461 pub tool_use_id: String,
462 pub content: Vec<ContentBlockParam>,
463 #[serde(rename = "is_error", skip_serializing_if = "Option::is_none")]
464 pub is_error: Option<bool>,
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
468#[serde(tag = "type")]
469pub enum ContentBlockParam {
470 #[serde(rename = "text")]
471 Text { text: String },
472 #[serde(rename = "image")]
473 Image { source: ImageSource },
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct ImageSource {
478 #[serde(rename = "type")]
479 pub source_type: String,
480 pub media_type: String,
481 pub data: String,
482}
483
484pub trait Tool: Send + Sync {
508 fn name(&self) -> &str;
512
513 fn aliases(&self) -> Option<&[String]> {
515 None
516 }
517
518 fn search_hint(&self) -> Option<&str> {
521 None
522 }
523
524 fn input_schema(&self) -> ToolInputSchema;
526
527 fn input_json_schema(&self) -> Option<ToolInputJsonSchema> {
529 None
530 }
531
532 fn output_schema(&self) -> Option<serde_json::Value> {
534 None
535 }
536
537 fn call(
539 &self,
540 args: serde_json::Value,
541 context: Arc<ToolUseContext>,
542 can_use_tool: Arc<
543 dyn Fn(
544 &ToolDefinition,
545 &serde_json::Value,
546 Arc<ToolUseContext>,
547 Arc<AssistantMessage>,
548 &str,
549 bool,
550 ) -> std::pin::Pin<
551 Box<
552 dyn Future<Output = Result<PermissionDecision, crate::error::AgentError>>
553 + Send,
554 >,
555 > + Send
556 + Sync,
557 >,
558 parent_message: Arc<AssistantMessage>,
559 on_progress: Option<Arc<dyn Fn(ToolProgress) + Send + Sync>>,
560 ) -> std::pin::Pin<
561 Box<dyn Future<Output = Result<ToolResult, crate::error::AgentError>> + Send + '_>,
562 >;
563
564 fn description(
566 &self,
567 input: serde_json::Value,
568 is_non_interactive_session: bool,
569 tool_permission_context: &ToolPermissionContext,
570 tools: &[ToolDefinition],
571 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send + '_>>;
572
573 fn validate_input(
578 &self,
579 _input: serde_json::Value,
580 _context: Arc<ToolUseContext>,
581 ) -> std::pin::Pin<Box<dyn Future<Output = ValidationResult> + Send + '_>> {
582 Box::pin(async { ValidationResult::Valid })
583 }
584
585 fn check_permissions(
588 &self,
589 input: serde_json::Value,
590 _context: Arc<ToolUseContext>,
591 ) -> std::pin::Pin<Box<dyn Future<Output = PermissionResult> + Send + '_>> {
592 Box::pin(async move {
593 let updated_input = input.as_object().map(|o| {
594 o.clone()
595 .into_iter()
596 .collect::<HashMap<String, serde_json::Value>>()
597 });
598 PermissionResult::Allow {
599 updated_input,
600 user_modified: None,
601 }
602 })
603 }
604
605 fn prepare_permission_matcher(
608 &self,
609 _input: serde_json::Value,
610 ) -> Option<Arc<dyn Fn(&str) -> bool + Send + Sync>> {
611 None
612 }
613
614 fn is_enabled(&self) -> bool {
618 true
619 }
620
621 fn is_concurrency_safe(&self, _input: serde_json::Value) -> bool {
623 false
624 }
625
626 fn is_read_only(&self, _input: serde_json::Value) -> bool {
628 false
629 }
630
631 fn is_destructive(&self, _input: serde_json::Value) -> bool {
634 false
635 }
636
637 fn inputs_equivalent(&self, _a: serde_json::Value, _b: serde_json::Value) -> bool {
639 false
640 }
641
642 fn max_result_size_chars(&self) -> usize {
644 usize::MAX
645 }
646
647 fn strict(&self) -> bool {
649 false
650 }
651
652 fn should_defer(&self) -> bool {
655 false
656 }
657
658 fn always_load(&self) -> bool {
660 false
661 }
662
663 fn mcp_info(&self) -> Option<McpToolInfo> {
665 None
666 }
667
668 fn is_mcp(&self) -> bool {
670 false
671 }
672
673 fn is_lsp(&self) -> bool {
675 false
676 }
677
678 fn interrupt_behavior(&self) -> &str {
687 "block"
688 }
689
690 fn is_search_or_read_command(&self, _input: serde_json::Value) -> SearchOrReadInfo {
695 SearchOrReadInfo {
696 is_search: false,
697 is_read: false,
698 is_list: false,
699 }
700 }
701
702 fn is_open_world(&self, _input: serde_json::Value) -> bool {
704 false
705 }
706
707 fn requires_user_interaction(&self) -> bool {
709 false
710 }
711
712 fn backfill_observable_input(&self, _input: &mut serde_json::Value) {}
715
716 fn get_path(&self, _input: serde_json::Value) -> Option<String> {
718 None
719 }
720
721 fn user_facing_name(&self, _input: Option<&serde_json::Value>) -> String {
723 self.name().to_string()
724 }
725
726 fn user_facing_name_background_color(
728 &self,
729 _input: Option<&serde_json::Value>,
730 ) -> Option<String> {
731 None
732 }
733
734 fn is_transparent_wrapper(&self) -> bool {
736 false
737 }
738
739 fn get_tool_use_summary(&self, _input: Option<&serde_json::Value>) -> Option<String> {
741 None
742 }
743
744 fn get_activity_description(&self, _input: Option<&serde_json::Value>) -> Option<String> {
746 None
747 }
748
749 fn to_auto_classifier_input(&self, _input: serde_json::Value) -> serde_json::Value {
751 serde_json::Value::String(String::new())
752 }
753
754 fn map_tool_result_to_tool_result_block_param(
756 &self,
757 content: serde_json::Value,
758 tool_use_id: &str,
759 ) -> ToolResultBlockParam;
760
761 fn render_tool_result_message(
764 &self,
765 _content: serde_json::Value,
766 _progress_messages: &[ProgressMessage],
767 _options: ToolResultRenderOptions,
768 ) -> Option<String> {
769 None
770 }
771
772 fn extract_search_text(&self, _out: serde_json::Value) -> String {
774 String::new()
775 }
776
777 fn render_tool_use_message(
779 &self,
780 input: serde_json::Value,
781 options: ToolUseRenderOptions,
782 ) -> String;
783
784 fn is_result_truncated(&self, _output: serde_json::Value) -> bool {
786 false
787 }
788
789 fn render_tool_use_tag(&self, _input: serde_json::Value) -> Option<String> {
791 None
792 }
793
794 fn render_tool_use_progress_message(
796 &self,
797 _progress_messages: &[ProgressMessage],
798 _options: ToolProgressRenderOptions,
799 ) -> Option<String> {
800 None
801 }
802
803 fn render_tool_use_queued_message(&self) -> Option<String> {
805 None
806 }
807
808 fn render_tool_use_rejected_message(
810 &self,
811 _input: serde_json::Value,
812 _options: ToolRejectedRenderOptions,
813 ) -> Option<String> {
814 None
815 }
816
817 fn render_tool_use_error_message(
819 &self,
820 _result: serde_json::Value,
821 _options: ToolErrorRenderOptions,
822 ) -> Option<String> {
823 None
824 }
825
826 fn render_grouped_tool_uses(
828 &self,
829 _tool_uses: Vec<GroupedToolUse>,
830 _options: GroupedToolUseRenderOptions,
831 ) -> Option<String> {
832 None
833 }
834
835 fn render_grouped_tool_use(
837 &self,
838 _param: serde_json::Value,
839 _is_resolved: bool,
840 _is_error: bool,
841 _is_in_progress: bool,
842 _progress_messages: &[ProgressMessage],
843 _result: Option<serde_json::Value>,
844 _options: GroupedToolUseRenderOptions,
845 ) -> Option<String> {
846 None
847 }
848
849 fn render_grouped_tool_use_fallback(
851 &self,
852 _tool_uses: Vec<GroupedToolUse>,
853 _options: GroupedToolUseRenderOptions,
854 ) -> Option<String> {
855 None
856 }
857
858 fn prompt(
860 &self,
861 get_tool_permission_context: Arc<
862 dyn Fn() -> std::pin::Pin<Box<dyn Future<Output = ToolPermissionContext> + Send>>
863 + Send
864 + Sync,
865 >,
866 tools: &[ToolDefinition],
867 agents: &[serde_json::Value],
868 allowed_agent_types: Option<&[String]>,
869 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send + '_>>;
870}
871
872#[derive(Debug, Clone)]
877pub struct SearchOrReadInfo {
878 pub is_search: bool,
879 pub is_read: bool,
880 pub is_list: bool,
881}
882
883#[derive(Debug, Clone)]
884pub struct McpToolInfo {
885 pub server_name: String,
886 pub tool_name: String,
887}
888
889#[derive(Debug, Clone)]
890pub struct ToolResultRenderOptions {
891 pub style: Option<String>,
892 pub theme: String,
893 pub tools: Vec<ToolDefinition>,
894 pub verbose: bool,
895 pub is_transcript_mode: bool,
896 pub is_brief_only: bool,
897 pub input: Option<serde_json::Value>,
898}
899
900#[derive(Debug, Clone)]
901pub struct ToolUseRenderOptions {
902 pub theme: String,
903 pub verbose: bool,
904 pub commands: Option<Vec<serde_json::Value>>,
905}
906
907#[derive(Debug, Clone)]
908pub struct ToolProgressRenderOptions {
909 pub tools: Vec<ToolDefinition>,
910 pub verbose: bool,
911 pub terminal_size: Option<TerminalSize>,
912 pub in_progress_tool_call_count: Option<usize>,
913 pub is_transcript_mode: bool,
914}
915
916#[derive(Debug, Clone)]
917pub struct TerminalSize {
918 pub columns: usize,
919 pub rows: usize,
920}
921
922#[derive(Debug, Clone)]
923pub struct ToolRejectedRenderOptions {
924 pub columns: usize,
925 pub messages: Vec<Message>,
926 pub style: Option<String>,
927 pub theme: String,
928 pub tools: Vec<ToolDefinition>,
929 pub verbose: bool,
930 pub progress_messages_for_message: Vec<ProgressMessage>,
931 pub is_transcript_mode: bool,
932}
933
934#[derive(Debug, Clone)]
935pub struct ToolErrorRenderOptions {
936 pub progress_messages_for_message: Vec<ProgressMessage>,
937 pub tools: Vec<ToolDefinition>,
938 pub verbose: bool,
939 pub is_transcript_mode: bool,
940}
941
942#[derive(Debug, Clone)]
943pub struct GroupedToolUse {
944 pub param: serde_json::Value,
945 pub is_resolved: bool,
946 pub is_error: bool,
947 pub is_in_progress: bool,
948 pub progress_messages: Vec<ProgressMessage>,
949 pub result: Option<GroupedToolUseResult>,
950}
951
952#[derive(Debug, Clone)]
953pub struct GroupedToolUseResult {
954 pub param: serde_json::Value,
955 pub output: serde_json::Value,
956}
957
958#[derive(Debug, Clone)]
959pub struct GroupedToolUseRenderOptions {
960 pub should_animate: bool,
961 pub tools: Vec<ToolDefinition>,
962}
963
964#[derive(Debug, Clone, Serialize, Deserialize)]
969#[serde(tag = "behavior", rename_all = "lowercase")]
970pub enum PermissionResult {
971 Allow {
972 #[serde(rename = "updatedInput", skip_serializing_if = "Option::is_none")]
973 updated_input: Option<HashMap<String, serde_json::Value>>,
974 #[serde(rename = "userModified", skip_serializing_if = "Option::is_none")]
975 user_modified: Option<bool>,
976 },
977 Deny {
978 message: String,
979 #[serde(rename = "toolUseID", skip_serializing_if = "Option::is_none")]
980 tool_use_id: Option<String>,
981 },
982 Ask {
983 message: String,
984 #[serde(rename = "updatedInput", skip_serializing_if = "Option::is_none")]
985 updated_input: Option<HashMap<String, serde_json::Value>>,
986 },
987 Passthrough {
988 message: String,
989 },
990}
991
992impl PermissionResult {
993 pub fn allow(input: HashMap<String, serde_json::Value>) -> Self {
995 PermissionResult::Allow {
996 updated_input: Some(input),
997 user_modified: None,
998 }
999 }
1000}
1001
1002#[derive(Debug, Clone, Serialize, Deserialize)]
1007#[serde(tag = "behavior", rename_all = "lowercase")]
1008pub enum PermissionDecision {
1009 Allow {
1010 #[serde(rename = "updatedInput", skip_serializing_if = "Option::is_none")]
1011 updated_input: Option<HashMap<String, serde_json::Value>>,
1012 },
1013 Deny {
1014 message: String,
1015 },
1016 Ask {
1017 message: String,
1018 },
1019}
1020
1021pub type Tools = Vec<ToolDefinition>;
1029
1030pub struct ToolDefaults {
1045 pub is_enabled: bool,
1046 pub is_concurrency_safe: bool,
1047 pub is_read_only: bool,
1048 pub is_destructive: bool,
1049 pub check_permissions: Arc<
1050 dyn Fn(
1051 serde_json::Value,
1052 ) -> std::pin::Pin<Box<dyn Future<Output = PermissionResult> + Send>>
1053 + Send
1054 + Sync,
1055 >,
1056 pub to_auto_classifier_input: Arc<dyn Fn(serde_json::Value) -> serde_json::Value + Send + Sync>,
1057 pub user_facing_name: Arc<dyn Fn() -> String + Send + Sync>,
1058}
1059
1060impl Default for ToolDefaults {
1061 fn default() -> Self {
1062 ToolDefaults {
1063 is_enabled: true,
1064 is_concurrency_safe: false,
1065 is_read_only: false,
1066 is_destructive: false,
1067 check_permissions: Arc::new(|input: serde_json::Value| {
1068 Box::pin(async move {
1069 PermissionResult::Allow {
1070 updated_input: Some(
1071 input
1072 .as_object()
1073 .cloned()
1074 .unwrap_or_default()
1075 .into_iter()
1076 .collect(),
1077 ),
1078 user_modified: None,
1079 }
1080 })
1081 }),
1082 to_auto_classifier_input: Arc::new(|_input: serde_json::Value| {
1083 serde_json::Value::String(String::new())
1084 }),
1085 user_facing_name: Arc::new(|| String::new()),
1086 }
1087 }
1088}
1089
1090pub struct ToolBuilder {
1117 name: String,
1118 aliases: Option<Vec<String>>,
1119 search_hint: Option<String>,
1120 input_schema: Option<ToolInputSchema>,
1121 input_json_schema: Option<ToolInputJsonSchema>,
1122 output_schema: Option<serde_json::Value>,
1123 call_fn: Option<
1124 Arc<
1125 dyn Fn(
1126 serde_json::Value,
1127 Arc<ToolUseContext>,
1128 Arc<
1129 dyn Fn(
1130 &ToolDefinition,
1131 &serde_json::Value,
1132 Arc<ToolUseContext>,
1133 Arc<AssistantMessage>,
1134 &str,
1135 bool,
1136 ) -> std::pin::Pin<
1137 Box<
1138 dyn Future<
1139 Output = Result<
1140 PermissionDecision,
1141 crate::error::AgentError,
1142 >,
1143 > + Send,
1144 >,
1145 > + Send
1146 + Sync,
1147 >,
1148 Arc<AssistantMessage>,
1149 Option<Arc<dyn Fn(ToolProgress) + Send + Sync>>,
1150 ) -> std::pin::Pin<
1151 Box<dyn Future<Output = Result<ToolResult, crate::error::AgentError>> + Send>,
1152 > + Send
1153 + Sync,
1154 >,
1155 >,
1156 description_fn: Option<
1157 Arc<
1158 dyn Fn(
1159 serde_json::Value,
1160 bool,
1161 &ToolPermissionContext,
1162 &[ToolDefinition],
1163 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send>>
1164 + Send
1165 + Sync,
1166 >,
1167 >,
1168 prompt_fn: Option<
1169 Arc<
1170 dyn Fn(
1171 Arc<
1172 dyn Fn() -> std::pin::Pin<
1173 Box<dyn Future<Output = ToolPermissionContext> + Send>,
1174 > + Send
1175 + Sync,
1176 >,
1177 &[ToolDefinition],
1178 &[serde_json::Value],
1179 Option<&[String]>,
1180 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send>>
1181 + Send
1182 + Sync,
1183 >,
1184 >,
1185 validate_input_fn: Option<
1186 Arc<
1187 dyn Fn(
1188 serde_json::Value,
1189 Arc<ToolUseContext>,
1190 )
1191 -> std::pin::Pin<Box<dyn Future<Output = ValidationResult> + Send>>
1192 + Send
1193 + Sync,
1194 >,
1195 >,
1196 check_permissions_fn: Option<
1197 Arc<
1198 dyn Fn(
1199 serde_json::Value,
1200 Arc<ToolUseContext>,
1201 )
1202 -> std::pin::Pin<Box<dyn Future<Output = PermissionResult> + Send>>
1203 + Send
1204 + Sync,
1205 >,
1206 >,
1207 prepare_permission_matcher_fn: Option<
1208 Arc<dyn Fn(serde_json::Value) -> Arc<dyn Fn(&str) -> bool + Send + Sync> + Send + Sync>,
1209 >,
1210 is_enabled: bool,
1211 is_concurrency_safe_fn: Option<Arc<dyn Fn(serde_json::Value) -> bool + Send + Sync>>,
1212 is_read_only_fn: Option<Arc<dyn Fn(serde_json::Value) -> bool + Send + Sync>>,
1213 is_destructive_fn: Option<Arc<dyn Fn(serde_json::Value) -> bool + Send + Sync>>,
1214 inputs_equivalent_fn:
1215 Option<Arc<dyn Fn(serde_json::Value, serde_json::Value) -> bool + Send + Sync>>,
1216 max_result_size_chars: usize,
1217 strict: bool,
1218 should_defer: bool,
1219 always_load: bool,
1220 mcp_info: Option<McpToolInfo>,
1221 is_mcp: bool,
1222 is_lsp: bool,
1223 interrupt_behavior: String,
1224 is_search_or_read_fn: Option<Arc<dyn Fn(serde_json::Value) -> SearchOrReadInfo + Send + Sync>>,
1225 is_open_world_fn: Option<Arc<dyn Fn(serde_json::Value) -> bool + Send + Sync>>,
1226 requires_user_interaction: bool,
1227 backfill_observable_input_fn: Option<Arc<dyn Fn(&mut serde_json::Value) + Send + Sync>>,
1228 get_path_fn: Option<Arc<dyn Fn(serde_json::Value) -> Option<String> + Send + Sync>>,
1229 user_facing_name_fn: Option<Arc<dyn Fn(Option<&serde_json::Value>) -> String + Send + Sync>>,
1230 user_facing_name_background_color_fn:
1231 Option<Arc<dyn Fn(Option<&serde_json::Value>) -> Option<String> + Send + Sync>>,
1232 is_transparent_wrapper: bool,
1233 get_tool_use_summary_fn:
1234 Option<Arc<dyn Fn(Option<&serde_json::Value>) -> Option<String> + Send + Sync>>,
1235 get_activity_description_fn:
1236 Option<Arc<dyn Fn(Option<&serde_json::Value>) -> Option<String> + Send + Sync>>,
1237 to_auto_classifier_input_fn:
1238 Option<Arc<dyn Fn(serde_json::Value) -> serde_json::Value + Send + Sync>>,
1239 map_tool_result_fn:
1240 Option<Arc<dyn Fn(serde_json::Value, &str) -> ToolResultBlockParam + Send + Sync>>,
1241 render_tool_result_message_fn: Option<
1242 Arc<
1243 dyn Fn(serde_json::Value, &[ProgressMessage], ToolResultRenderOptions) -> Option<String>
1244 + Send
1245 + Sync,
1246 >,
1247 >,
1248 extract_search_text_fn: Option<Arc<dyn Fn(serde_json::Value) -> String + Send + Sync>>,
1249 render_tool_use_message_fn:
1250 Option<Arc<dyn Fn(serde_json::Value, ToolUseRenderOptions) -> String + Send + Sync>>,
1251 is_result_truncated_fn: Option<Arc<dyn Fn(serde_json::Value) -> bool + Send + Sync>>,
1252 render_tool_use_tag_fn: Option<Arc<dyn Fn(serde_json::Value) -> Option<String> + Send + Sync>>,
1253 render_tool_use_progress_message_fn: Option<
1254 Arc<dyn Fn(&[ProgressMessage], ToolProgressRenderOptions) -> Option<String> + Send + Sync>,
1255 >,
1256 render_tool_use_queued_message_fn: Option<Arc<dyn Fn() -> Option<String> + Send + Sync>>,
1257 render_tool_use_rejected_message_fn: Option<
1258 Arc<dyn Fn(serde_json::Value, ToolRejectedRenderOptions) -> Option<String> + Send + Sync>,
1259 >,
1260 render_tool_use_error_message_fn: Option<
1261 Arc<dyn Fn(serde_json::Value, ToolErrorRenderOptions) -> Option<String> + Send + Sync>,
1262 >,
1263 render_grouped_tool_uses_fn: Option<
1264 Arc<
1265 dyn Fn(Vec<GroupedToolUse>, GroupedToolUseRenderOptions) -> Option<String>
1266 + Send
1267 + Sync,
1268 >,
1269 >,
1270 render_grouped_tool_use_fn: Option<
1271 Arc<
1272 dyn Fn(
1273 serde_json::Value,
1274 bool,
1275 bool,
1276 bool,
1277 &[ProgressMessage],
1278 Option<serde_json::Value>,
1279 GroupedToolUseRenderOptions,
1280 ) -> Option<String>
1281 + Send
1282 + Sync,
1283 >,
1284 >,
1285 render_grouped_tool_use_fallback_fn: Option<
1286 Arc<
1287 dyn Fn(Vec<GroupedToolUse>, GroupedToolUseRenderOptions) -> Option<String>
1288 + Send
1289 + Sync,
1290 >,
1291 >,
1292}
1293
1294impl ToolBuilder {
1295 pub fn new(name: &str) -> Self {
1297 ToolBuilder {
1298 name: name.to_string(),
1299 aliases: None,
1300 search_hint: None,
1301 input_schema: None,
1302 input_json_schema: None,
1303 output_schema: None,
1304 call_fn: None,
1305 description_fn: None,
1306 prompt_fn: None,
1307 validate_input_fn: None,
1308 check_permissions_fn: None,
1309 prepare_permission_matcher_fn: None,
1310 is_enabled: true,
1311 is_concurrency_safe_fn: None,
1312 is_read_only_fn: None,
1313 is_destructive_fn: None,
1314 inputs_equivalent_fn: None,
1315 max_result_size_chars: usize::MAX,
1316 strict: false,
1317 should_defer: false,
1318 always_load: false,
1319 mcp_info: None,
1320 is_mcp: false,
1321 is_lsp: false,
1322 interrupt_behavior: "block".to_string(),
1323 is_search_or_read_fn: None,
1324 is_open_world_fn: None,
1325 requires_user_interaction: false,
1326 backfill_observable_input_fn: None,
1327 get_path_fn: None,
1328 user_facing_name_fn: None,
1329 user_facing_name_background_color_fn: None,
1330 is_transparent_wrapper: false,
1331 get_tool_use_summary_fn: None,
1332 get_activity_description_fn: None,
1333 to_auto_classifier_input_fn: None,
1334 map_tool_result_fn: None,
1335 render_tool_result_message_fn: None,
1336 extract_search_text_fn: None,
1337 render_tool_use_message_fn: None,
1338 is_result_truncated_fn: None,
1339 render_tool_use_tag_fn: None,
1340 render_tool_use_progress_message_fn: None,
1341 render_tool_use_queued_message_fn: None,
1342 render_tool_use_rejected_message_fn: None,
1343 render_tool_use_error_message_fn: None,
1344 render_grouped_tool_uses_fn: None,
1345 render_grouped_tool_use_fn: None,
1346 render_grouped_tool_use_fallback_fn: None,
1347 }
1348 }
1349
1350 pub fn aliases(mut self, aliases: Vec<String>) -> Self {
1351 self.aliases = Some(aliases);
1352 self
1353 }
1354
1355 pub fn search_hint(mut self, hint: &str) -> Self {
1356 self.search_hint = Some(hint.to_string());
1357 self
1358 }
1359
1360 pub fn input_schema(mut self, schema: ToolInputSchema) -> Self {
1361 self.input_schema = Some(schema);
1362 self
1363 }
1364
1365 pub fn input_json_schema(mut self, schema: ToolInputJsonSchema) -> Self {
1366 self.input_json_schema = Some(schema);
1367 self
1368 }
1369
1370 pub fn output_schema(mut self, schema: serde_json::Value) -> Self {
1371 self.output_schema = Some(schema);
1372 self
1373 }
1374
1375 pub fn call_fn<F>(mut self, f: F) -> Self
1376 where
1377 F: Fn(
1378 serde_json::Value,
1379 Arc<ToolUseContext>,
1380 Arc<
1381 dyn Fn(
1382 &ToolDefinition,
1383 &serde_json::Value,
1384 Arc<ToolUseContext>,
1385 Arc<AssistantMessage>,
1386 &str,
1387 bool,
1388 ) -> std::pin::Pin<
1389 Box<
1390 dyn Future<
1391 Output = Result<
1392 PermissionDecision,
1393 crate::error::AgentError,
1394 >,
1395 > + Send,
1396 >,
1397 > + Send
1398 + Sync,
1399 >,
1400 Arc<AssistantMessage>,
1401 Option<Arc<dyn Fn(ToolProgress) + Send + Sync>>,
1402 ) -> std::pin::Pin<
1403 Box<dyn Future<Output = Result<ToolResult, crate::error::AgentError>> + Send>,
1404 > + Send
1405 + Sync
1406 + 'static,
1407 {
1408 self.call_fn = Some(Arc::new(f));
1409 self
1410 }
1411
1412 pub fn description_fn<F>(mut self, f: F) -> Self
1413 where
1414 F: Fn(
1415 serde_json::Value,
1416 bool,
1417 &ToolPermissionContext,
1418 &[ToolDefinition],
1419 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send>>
1420 + Send
1421 + Sync
1422 + 'static,
1423 {
1424 self.description_fn = Some(Arc::new(f));
1425 self
1426 }
1427
1428 pub fn prompt_fn<F>(mut self, f: F) -> Self
1429 where
1430 F: Fn(
1431 Arc<
1432 dyn Fn()
1433 -> std::pin::Pin<Box<dyn Future<Output = ToolPermissionContext> + Send>>
1434 + Send
1435 + Sync,
1436 >,
1437 &[ToolDefinition],
1438 &[serde_json::Value],
1439 Option<&[String]>,
1440 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send>>
1441 + Send
1442 + Sync
1443 + 'static,
1444 {
1445 self.prompt_fn = Some(Arc::new(f));
1446 self
1447 }
1448
1449 pub fn validate_input_fn<F>(mut self, f: F) -> Self
1450 where
1451 F: Fn(
1452 serde_json::Value,
1453 Arc<ToolUseContext>,
1454 ) -> std::pin::Pin<Box<dyn Future<Output = ValidationResult> + Send>>
1455 + Send
1456 + Sync
1457 + 'static,
1458 {
1459 self.validate_input_fn = Some(Arc::new(f));
1460 self
1461 }
1462
1463 pub fn check_permissions_fn<F>(mut self, f: F) -> Self
1464 where
1465 F: Fn(
1466 serde_json::Value,
1467 Arc<ToolUseContext>,
1468 ) -> std::pin::Pin<Box<dyn Future<Output = PermissionResult> + Send>>
1469 + Send
1470 + Sync
1471 + 'static,
1472 {
1473 self.check_permissions_fn = Some(Arc::new(f));
1474 self
1475 }
1476
1477 pub fn prepare_permission_matcher_fn<F>(mut self, f: F) -> Self
1478 where
1479 F: Fn(serde_json::Value) -> Arc<dyn Fn(&str) -> bool + Send + Sync> + Send + Sync + 'static,
1480 {
1481 self.prepare_permission_matcher_fn = Some(Arc::new(f));
1482 self
1483 }
1484
1485 pub fn is_enabled(mut self, enabled: bool) -> Self {
1486 self.is_enabled = enabled;
1487 self
1488 }
1489
1490 pub fn is_concurrency_safe_fn<F>(mut self, f: F) -> Self
1491 where
1492 F: Fn(serde_json::Value) -> bool + Send + Sync + 'static,
1493 {
1494 self.is_concurrency_safe_fn = Some(Arc::new(f));
1495 self
1496 }
1497
1498 pub fn is_read_only_fn<F>(mut self, f: F) -> Self
1499 where
1500 F: Fn(serde_json::Value) -> bool + Send + Sync + 'static,
1501 {
1502 self.is_read_only_fn = Some(Arc::new(f));
1503 self
1504 }
1505
1506 pub fn is_destructive_fn<F>(mut self, f: F) -> Self
1507 where
1508 F: Fn(serde_json::Value) -> bool + Send + Sync + 'static,
1509 {
1510 self.is_destructive_fn = Some(Arc::new(f));
1511 self
1512 }
1513
1514 pub fn inputs_equivalent_fn<F>(mut self, f: F) -> Self
1515 where
1516 F: Fn(serde_json::Value, serde_json::Value) -> bool + Send + Sync + 'static,
1517 {
1518 self.inputs_equivalent_fn = Some(Arc::new(f));
1519 self
1520 }
1521
1522 pub fn max_result_size_chars(mut self, size: usize) -> Self {
1523 self.max_result_size_chars = size;
1524 self
1525 }
1526
1527 pub fn strict(mut self, strict: bool) -> Self {
1528 self.strict = strict;
1529 self
1530 }
1531
1532 pub fn should_defer(mut self, defer: bool) -> Self {
1533 self.should_defer = defer;
1534 self
1535 }
1536
1537 pub fn always_load(mut self, always: bool) -> Self {
1538 self.always_load = always;
1539 self
1540 }
1541
1542 pub fn mcp_info(mut self, server_name: &str, tool_name: &str) -> Self {
1543 self.mcp_info = Some(McpToolInfo {
1544 server_name: server_name.to_string(),
1545 tool_name: tool_name.to_string(),
1546 });
1547 self
1548 }
1549
1550 pub fn is_mcp(mut self, is_mcp: bool) -> Self {
1551 self.is_mcp = is_mcp;
1552 self
1553 }
1554
1555 pub fn is_lsp(mut self, is_lsp: bool) -> Self {
1556 self.is_lsp = is_lsp;
1557 self
1558 }
1559
1560 pub fn interrupt_behavior(mut self, behavior: &str) -> Self {
1561 self.interrupt_behavior = behavior.to_string();
1562 self
1563 }
1564
1565 pub fn is_search_or_read_fn<F>(mut self, f: F) -> Self
1566 where
1567 F: Fn(serde_json::Value) -> SearchOrReadInfo + Send + Sync + 'static,
1568 {
1569 self.is_search_or_read_fn = Some(Arc::new(f));
1570 self
1571 }
1572
1573 pub fn is_open_world_fn<F>(mut self, f: F) -> Self
1574 where
1575 F: Fn(serde_json::Value) -> bool + Send + Sync + 'static,
1576 {
1577 self.is_open_world_fn = Some(Arc::new(f));
1578 self
1579 }
1580
1581 pub fn requires_user_interaction(mut self, requires: bool) -> Self {
1582 self.requires_user_interaction = requires;
1583 self
1584 }
1585
1586 pub fn backfill_observable_input_fn<F>(mut self, f: F) -> Self
1587 where
1588 F: Fn(&mut serde_json::Value) + Send + Sync + 'static,
1589 {
1590 self.backfill_observable_input_fn = Some(Arc::new(f));
1591 self
1592 }
1593
1594 pub fn get_path_fn<F>(mut self, f: F) -> Self
1595 where
1596 F: Fn(serde_json::Value) -> Option<String> + Send + Sync + 'static,
1597 {
1598 self.get_path_fn = Some(Arc::new(f));
1599 self
1600 }
1601
1602 pub fn user_facing_name_fn<F>(mut self, f: F) -> Self
1603 where
1604 F: Fn(Option<&serde_json::Value>) -> String + Send + Sync + 'static,
1605 {
1606 self.user_facing_name_fn = Some(Arc::new(f));
1607 self
1608 }
1609
1610 pub fn user_facing_name_background_color_fn<F>(mut self, f: F) -> Self
1611 where
1612 F: Fn(Option<&serde_json::Value>) -> Option<String> + Send + Sync + 'static,
1613 {
1614 self.user_facing_name_background_color_fn = Some(Arc::new(f));
1615 self
1616 }
1617
1618 pub fn is_transparent_wrapper(mut self, is_transparent: bool) -> Self {
1619 self.is_transparent_wrapper = is_transparent;
1620 self
1621 }
1622
1623 pub fn get_tool_use_summary_fn<F>(mut self, f: F) -> Self
1624 where
1625 F: Fn(Option<&serde_json::Value>) -> Option<String> + Send + Sync + 'static,
1626 {
1627 self.get_tool_use_summary_fn = Some(Arc::new(f));
1628 self
1629 }
1630
1631 pub fn get_activity_description_fn<F>(mut self, f: F) -> Self
1632 where
1633 F: Fn(Option<&serde_json::Value>) -> Option<String> + Send + Sync + 'static,
1634 {
1635 self.get_activity_description_fn = Some(Arc::new(f));
1636 self
1637 }
1638
1639 pub fn to_auto_classifier_input_fn<F>(mut self, f: F) -> Self
1640 where
1641 F: Fn(serde_json::Value) -> serde_json::Value + Send + Sync + 'static,
1642 {
1643 self.to_auto_classifier_input_fn = Some(Arc::new(f));
1644 self
1645 }
1646
1647 pub fn map_tool_result_fn<F>(mut self, f: F) -> Self
1648 where
1649 F: Fn(serde_json::Value, &str) -> ToolResultBlockParam + Send + Sync + 'static,
1650 {
1651 self.map_tool_result_fn = Some(Arc::new(f));
1652 self
1653 }
1654
1655 pub fn render_tool_result_message_fn<F>(mut self, f: F) -> Self
1656 where
1657 F: Fn(serde_json::Value, &[ProgressMessage], ToolResultRenderOptions) -> Option<String>
1658 + Send
1659 + Sync
1660 + 'static,
1661 {
1662 self.render_tool_result_message_fn = Some(Arc::new(f));
1663 self
1664 }
1665
1666 pub fn extract_search_text_fn<F>(mut self, f: F) -> Self
1667 where
1668 F: Fn(serde_json::Value) -> String + Send + Sync + 'static,
1669 {
1670 self.extract_search_text_fn = Some(Arc::new(f));
1671 self
1672 }
1673
1674 pub fn render_tool_use_message_fn<F>(mut self, f: F) -> Self
1675 where
1676 F: Fn(serde_json::Value, ToolUseRenderOptions) -> String + Send + Sync + 'static,
1677 {
1678 self.render_tool_use_message_fn = Some(Arc::new(f));
1679 self
1680 }
1681
1682 pub fn is_result_truncated_fn<F>(mut self, f: F) -> Self
1683 where
1684 F: Fn(serde_json::Value) -> bool + Send + Sync + 'static,
1685 {
1686 self.is_result_truncated_fn = Some(Arc::new(f));
1687 self
1688 }
1689
1690 pub fn render_tool_use_tag_fn<F>(mut self, f: F) -> Self
1691 where
1692 F: Fn(serde_json::Value) -> Option<String> + Send + Sync + 'static,
1693 {
1694 self.render_tool_use_tag_fn = Some(Arc::new(f));
1695 self
1696 }
1697
1698 pub fn render_tool_use_progress_message_fn<F>(mut self, f: F) -> Self
1699 where
1700 F: Fn(&[ProgressMessage], ToolProgressRenderOptions) -> Option<String>
1701 + Send
1702 + Sync
1703 + 'static,
1704 {
1705 self.render_tool_use_progress_message_fn = Some(Arc::new(f));
1706 self
1707 }
1708
1709 pub fn render_tool_use_queued_message_fn<F>(mut self, f: F) -> Self
1710 where
1711 F: Fn() -> Option<String> + Send + Sync + 'static,
1712 {
1713 self.render_tool_use_queued_message_fn = Some(Arc::new(f));
1714 self
1715 }
1716
1717 pub fn render_tool_use_rejected_message_fn<F>(mut self, f: F) -> Self
1718 where
1719 F: Fn(serde_json::Value, ToolRejectedRenderOptions) -> Option<String>
1720 + Send
1721 + Sync
1722 + 'static,
1723 {
1724 self.render_tool_use_rejected_message_fn = Some(Arc::new(f));
1725 self
1726 }
1727
1728 pub fn render_tool_use_error_message_fn<F>(mut self, f: F) -> Self
1729 where
1730 F: Fn(serde_json::Value, ToolErrorRenderOptions) -> Option<String> + Send + Sync + 'static,
1731 {
1732 self.render_tool_use_error_message_fn = Some(Arc::new(f));
1733 self
1734 }
1735
1736 pub fn render_grouped_tool_uses_fn<F>(mut self, f: F) -> Self
1737 where
1738 F: Fn(Vec<GroupedToolUse>, GroupedToolUseRenderOptions) -> Option<String>
1739 + Send
1740 + Sync
1741 + 'static,
1742 {
1743 self.render_grouped_tool_uses_fn = Some(Arc::new(f));
1744 self
1745 }
1746
1747 pub fn render_grouped_tool_use_fn<F>(mut self, f: F) -> Self
1748 where
1749 F: Fn(
1750 serde_json::Value,
1751 bool,
1752 bool,
1753 bool,
1754 &[ProgressMessage],
1755 Option<serde_json::Value>,
1756 GroupedToolUseRenderOptions,
1757 ) -> Option<String>
1758 + Send
1759 + Sync
1760 + 'static,
1761 {
1762 self.render_grouped_tool_use_fn = Some(Arc::new(f));
1763 self
1764 }
1765
1766 pub fn render_grouped_tool_use_fallback_fn<F>(mut self, f: F) -> Self
1767 where
1768 F: Fn(Vec<GroupedToolUse>, GroupedToolUseRenderOptions) -> Option<String>
1769 + Send
1770 + Sync
1771 + 'static,
1772 {
1773 self.render_grouped_tool_use_fallback_fn = Some(Arc::new(f));
1774 self
1775 }
1776
1777 pub fn build(self) -> Box<dyn Tool> {
1782 let name = self.name.clone();
1783 Box::new(BuiltTool { inner: self })
1784 }
1785}
1786
1787struct BuiltTool {
1790 inner: ToolBuilder,
1791}
1792
1793impl Tool for BuiltTool {
1794 fn name(&self) -> &str {
1795 &self.inner.name
1796 }
1797
1798 fn aliases(&self) -> Option<&[String]> {
1799 self.inner.aliases.as_deref()
1800 }
1801
1802 fn search_hint(&self) -> Option<&str> {
1803 self.inner.search_hint.as_deref()
1804 }
1805
1806 fn input_schema(&self) -> ToolInputSchema {
1807 self.inner
1808 .input_schema
1809 .clone()
1810 .unwrap_or_else(|| ToolInputSchema {
1811 schema_type: "object".to_string(),
1812 properties: serde_json::json!({}),
1813 required: None,
1814 })
1815 }
1816
1817 fn input_json_schema(&self) -> Option<ToolInputJsonSchema> {
1818 self.inner.input_json_schema.clone()
1819 }
1820
1821 fn output_schema(&self) -> Option<serde_json::Value> {
1822 self.inner.output_schema.clone()
1823 }
1824
1825 fn call(
1826 &self,
1827 args: serde_json::Value,
1828 context: Arc<ToolUseContext>,
1829 can_use_tool: Arc<
1830 dyn Fn(
1831 &ToolDefinition,
1832 &serde_json::Value,
1833 Arc<ToolUseContext>,
1834 Arc<AssistantMessage>,
1835 &str,
1836 bool,
1837 ) -> std::pin::Pin<
1838 Box<
1839 dyn Future<Output = Result<PermissionDecision, crate::error::AgentError>>
1840 + Send,
1841 >,
1842 > + Send
1843 + Sync,
1844 >,
1845 parent_message: Arc<AssistantMessage>,
1846 on_progress: Option<Arc<dyn Fn(ToolProgress) + Send + Sync>>,
1847 ) -> std::pin::Pin<
1848 Box<dyn Future<Output = Result<ToolResult, crate::error::AgentError>> + Send + '_>,
1849 > {
1850 if let Some(f) = &self.inner.call_fn {
1851 let f = Arc::clone(f);
1852 let can_use_tool = Arc::clone(&can_use_tool);
1853 let context = Arc::clone(&context);
1854 let parent_message = Arc::clone(&parent_message);
1855 let on_progress = on_progress.clone();
1856 Box::pin(
1857 async move { f(args, context, can_use_tool, parent_message, on_progress).await },
1858 )
1859 } else {
1860 Box::pin(async {
1861 Err(crate::error::AgentError::Tool(format!(
1862 "Tool '{}' has no call implementation",
1863 self.inner.name
1864 )))
1865 })
1866 }
1867 }
1868
1869 fn description(
1870 &self,
1871 input: serde_json::Value,
1872 is_non_interactive_session: bool,
1873 tool_permission_context: &ToolPermissionContext,
1874 tools: &[ToolDefinition],
1875 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send + '_>> {
1876 if let Some(f) = &self.inner.description_fn {
1877 let f = Arc::clone(f);
1878 let tools = tools.to_vec();
1879 let tpc = tool_permission_context.clone();
1880 Box::pin(async move { f(input, is_non_interactive_session, &tpc, &tools).await })
1881 } else {
1882 Box::pin(async move { format!("Tool: {}", self.inner.name) })
1883 }
1884 }
1885
1886 fn validate_input(
1887 &self,
1888 input: serde_json::Value,
1889 context: Arc<ToolUseContext>,
1890 ) -> std::pin::Pin<Box<dyn Future<Output = ValidationResult> + Send + '_>> {
1891 if let Some(f) = &self.inner.validate_input_fn {
1892 let f = Arc::clone(f);
1893 let context = Arc::clone(&context);
1894 Box::pin(async move { f(input, context).await })
1895 } else {
1896 Box::pin(async { ValidationResult::Valid })
1897 }
1898 }
1899
1900 fn check_permissions(
1901 &self,
1902 input: serde_json::Value,
1903 context: Arc<ToolUseContext>,
1904 ) -> std::pin::Pin<Box<dyn Future<Output = PermissionResult> + Send + '_>> {
1905 if let Some(f) = &self.inner.check_permissions_fn {
1906 let f = Arc::clone(f);
1907 let context = Arc::clone(&context);
1908 Box::pin(async move { f(input, context).await })
1909 } else {
1910 Box::pin(async move {
1911 PermissionResult::Allow {
1912 updated_input: input.as_object().map(|o| o.clone().into_iter().collect()),
1913 user_modified: None,
1914 }
1915 })
1916 }
1917 }
1918
1919 fn prepare_permission_matcher(
1920 &self,
1921 input: serde_json::Value,
1922 ) -> Option<Arc<dyn Fn(&str) -> bool + Send + Sync>> {
1923 self.inner
1924 .prepare_permission_matcher_fn
1925 .as_ref()
1926 .map(|f| f(input))
1927 }
1928
1929 fn is_enabled(&self) -> bool {
1930 self.inner.is_enabled
1931 }
1932
1933 fn is_concurrency_safe(&self, input: serde_json::Value) -> bool {
1934 self.inner
1935 .is_concurrency_safe_fn
1936 .as_ref()
1937 .map_or(false, |f| f(input))
1938 }
1939
1940 fn is_read_only(&self, input: serde_json::Value) -> bool {
1941 self.inner
1942 .is_read_only_fn
1943 .as_ref()
1944 .map_or(false, |f| f(input))
1945 }
1946
1947 fn is_destructive(&self, input: serde_json::Value) -> bool {
1948 self.inner
1949 .is_destructive_fn
1950 .as_ref()
1951 .map_or(false, |f| f(input))
1952 }
1953
1954 fn inputs_equivalent(&self, a: serde_json::Value, b: serde_json::Value) -> bool {
1955 self.inner
1956 .inputs_equivalent_fn
1957 .as_ref()
1958 .map_or(false, |f| f(a, b))
1959 }
1960
1961 fn max_result_size_chars(&self) -> usize {
1962 self.inner.max_result_size_chars
1963 }
1964
1965 fn strict(&self) -> bool {
1966 self.inner.strict
1967 }
1968
1969 fn should_defer(&self) -> bool {
1970 self.inner.should_defer
1971 }
1972
1973 fn always_load(&self) -> bool {
1974 self.inner.always_load
1975 }
1976
1977 fn mcp_info(&self) -> Option<McpToolInfo> {
1978 self.inner.mcp_info.clone()
1979 }
1980
1981 fn is_mcp(&self) -> bool {
1982 self.inner.is_mcp
1983 }
1984
1985 fn is_lsp(&self) -> bool {
1986 self.inner.is_lsp
1987 }
1988
1989 fn interrupt_behavior(&self) -> &str {
1990 &self.inner.interrupt_behavior
1991 }
1992
1993 fn is_search_or_read_command(&self, input: serde_json::Value) -> SearchOrReadInfo {
1994 self.inner.is_search_or_read_fn.as_ref().map_or(
1995 SearchOrReadInfo {
1996 is_search: false,
1997 is_read: false,
1998 is_list: false,
1999 },
2000 |f| f(input),
2001 )
2002 }
2003
2004 fn is_open_world(&self, input: serde_json::Value) -> bool {
2005 self.inner
2006 .is_open_world_fn
2007 .as_ref()
2008 .map_or(false, |f| f(input))
2009 }
2010
2011 fn requires_user_interaction(&self) -> bool {
2012 self.inner.requires_user_interaction
2013 }
2014
2015 fn backfill_observable_input(&self, input: &mut serde_json::Value) {
2016 if let Some(f) = &self.inner.backfill_observable_input_fn {
2017 f(input);
2018 }
2019 }
2020
2021 fn get_path(&self, input: serde_json::Value) -> Option<String> {
2022 self.inner.get_path_fn.as_ref().and_then(|f| f(input))
2023 }
2024
2025 fn user_facing_name(&self, input: Option<&serde_json::Value>) -> String {
2026 self.inner
2027 .user_facing_name_fn
2028 .as_ref()
2029 .map(|f| f(input))
2030 .unwrap_or_else(|| self.inner.name.clone())
2031 }
2032
2033 fn user_facing_name_background_color(
2034 &self,
2035 input: Option<&serde_json::Value>,
2036 ) -> Option<String> {
2037 self.inner
2038 .user_facing_name_background_color_fn
2039 .as_ref()
2040 .and_then(|f| f(input))
2041 }
2042
2043 fn is_transparent_wrapper(&self) -> bool {
2044 self.inner.is_transparent_wrapper
2045 }
2046
2047 fn get_tool_use_summary(&self, input: Option<&serde_json::Value>) -> Option<String> {
2048 self.inner
2049 .get_tool_use_summary_fn
2050 .as_ref()
2051 .and_then(|f| f(input))
2052 }
2053
2054 fn get_activity_description(&self, input: Option<&serde_json::Value>) -> Option<String> {
2055 self.inner
2056 .get_activity_description_fn
2057 .as_ref()
2058 .and_then(|f| f(input))
2059 }
2060
2061 fn to_auto_classifier_input(&self, input: serde_json::Value) -> serde_json::Value {
2062 self.inner
2063 .to_auto_classifier_input_fn
2064 .as_ref()
2065 .map_or(serde_json::Value::String(String::new()), |f| f(input))
2066 }
2067
2068 fn map_tool_result_to_tool_result_block_param(
2069 &self,
2070 content: serde_json::Value,
2071 tool_use_id: &str,
2072 ) -> ToolResultBlockParam {
2073 if let Some(f) = &self.inner.map_tool_result_fn {
2074 f(content, tool_use_id)
2075 } else {
2076 ToolResultBlockParam {
2077 block_type: "tool_result".to_string(),
2078 tool_use_id: tool_use_id.to_string(),
2079 content: vec![ContentBlockParam::Text {
2080 text: content.to_string(),
2081 }],
2082 is_error: None,
2083 }
2084 }
2085 }
2086
2087 fn render_tool_result_message(
2088 &self,
2089 content: serde_json::Value,
2090 progress_messages: &[ProgressMessage],
2091 options: ToolResultRenderOptions,
2092 ) -> Option<String> {
2093 self.inner
2094 .render_tool_result_message_fn
2095 .as_ref()
2096 .and_then(|f| f(content, progress_messages, options))
2097 }
2098
2099 fn extract_search_text(&self, out: serde_json::Value) -> String {
2100 self.inner
2101 .extract_search_text_fn
2102 .as_ref()
2103 .map_or(String::new(), |f| f(out))
2104 }
2105
2106 fn render_tool_use_message(
2107 &self,
2108 input: serde_json::Value,
2109 options: ToolUseRenderOptions,
2110 ) -> String {
2111 if let Some(f) = &self.inner.render_tool_use_message_fn {
2112 f(input, options)
2113 } else {
2114 format!("[Tool: {}]", self.inner.name)
2115 }
2116 }
2117
2118 fn is_result_truncated(&self, output: serde_json::Value) -> bool {
2119 self.inner
2120 .is_result_truncated_fn
2121 .as_ref()
2122 .map_or(false, |f| f(output))
2123 }
2124
2125 fn render_tool_use_tag(&self, input: serde_json::Value) -> Option<String> {
2126 self.inner
2127 .render_tool_use_tag_fn
2128 .as_ref()
2129 .and_then(|f| f(input))
2130 }
2131
2132 fn render_tool_use_progress_message(
2133 &self,
2134 progress_messages: &[ProgressMessage],
2135 options: ToolProgressRenderOptions,
2136 ) -> Option<String> {
2137 self.inner
2138 .render_tool_use_progress_message_fn
2139 .as_ref()
2140 .and_then(|f| f(progress_messages, options))
2141 }
2142
2143 fn render_tool_use_queued_message(&self) -> Option<String> {
2144 self.inner
2145 .render_tool_use_queued_message_fn
2146 .as_ref()
2147 .and_then(|f| f())
2148 }
2149
2150 fn render_tool_use_rejected_message(
2151 &self,
2152 input: serde_json::Value,
2153 options: ToolRejectedRenderOptions,
2154 ) -> Option<String> {
2155 self.inner
2156 .render_tool_use_rejected_message_fn
2157 .as_ref()
2158 .and_then(|f| f(input, options))
2159 }
2160
2161 fn render_tool_use_error_message(
2162 &self,
2163 result: serde_json::Value,
2164 options: ToolErrorRenderOptions,
2165 ) -> Option<String> {
2166 self.inner
2167 .render_tool_use_error_message_fn
2168 .as_ref()
2169 .and_then(|f| f(result, options))
2170 }
2171
2172 fn render_grouped_tool_uses(
2173 &self,
2174 tool_uses: Vec<GroupedToolUse>,
2175 options: GroupedToolUseRenderOptions,
2176 ) -> Option<String> {
2177 self.inner
2178 .render_grouped_tool_uses_fn
2179 .as_ref()
2180 .and_then(|f| f(tool_uses, options))
2181 }
2182
2183 fn render_grouped_tool_use(
2184 &self,
2185 param: serde_json::Value,
2186 is_resolved: bool,
2187 is_error: bool,
2188 is_in_progress: bool,
2189 progress_messages: &[ProgressMessage],
2190 result: Option<serde_json::Value>,
2191 options: GroupedToolUseRenderOptions,
2192 ) -> Option<String> {
2193 self.inner
2194 .render_grouped_tool_use_fn
2195 .as_ref()
2196 .and_then(|f| {
2197 f(
2198 param,
2199 is_resolved,
2200 is_error,
2201 is_in_progress,
2202 progress_messages,
2203 result,
2204 options,
2205 )
2206 })
2207 }
2208
2209 fn render_grouped_tool_use_fallback(
2210 &self,
2211 tool_uses: Vec<GroupedToolUse>,
2212 options: GroupedToolUseRenderOptions,
2213 ) -> Option<String> {
2214 self.inner
2215 .render_grouped_tool_use_fallback_fn
2216 .as_ref()
2217 .and_then(|f| f(tool_uses, options))
2218 }
2219
2220 fn prompt(
2221 &self,
2222 get_tool_permission_context: Arc<
2223 dyn Fn() -> std::pin::Pin<Box<dyn Future<Output = ToolPermissionContext> + Send>>
2224 + Send
2225 + Sync,
2226 >,
2227 tools: &[ToolDefinition],
2228 agents: &[serde_json::Value],
2229 allowed_agent_types: Option<&[String]>,
2230 ) -> std::pin::Pin<Box<dyn Future<Output = String> + Send + '_>> {
2231 if let Some(f) = &self.inner.prompt_fn {
2232 let f = Arc::clone(f);
2233 let tools = tools.to_vec();
2234 let agents = agents.to_vec();
2235 let allowed_agent_types = allowed_agent_types.map(|s| s.to_vec());
2236 Box::pin(async move {
2237 f(
2238 get_tool_permission_context,
2239 &tools,
2240 &agents,
2241 allowed_agent_types.as_deref(),
2242 )
2243 .await
2244 })
2245 } else {
2246 Box::pin(async move { format!("Use the {} tool.", self.inner.name) })
2247 }
2248 }
2249}
2250
2251